mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-24 16:53:50 +02:00
bug 560330 remove \${ "to not resolve" functionality
This change causes incompatibility for users using the \${ to not expand environment variables. Tested with sloeber (700+ projects) Change-Id: If327f055a41c309c475e17e0239a30e7518c3b23 Signed-off-by: jantje <eclipse@baeyens.it>
This commit is contained in:
parent
7c57855e2f
commit
4fd6a0f49f
2 changed files with 60 additions and 52 deletions
|
@ -13,6 +13,8 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.utils;
|
package org.eclipse.cdt.utils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
|
import org.eclipse.cdt.core.cdtvariables.CdtVariableException;
|
||||||
import org.eclipse.cdt.core.cdtvariables.ICdtVariableStatus;
|
import org.eclipse.cdt.core.cdtvariables.ICdtVariableStatus;
|
||||||
import org.eclipse.cdt.utils.cdtvariables.CdtVariableResolver;
|
import org.eclipse.cdt.utils.cdtvariables.CdtVariableResolver;
|
||||||
|
@ -23,6 +25,7 @@ import junit.framework.TestCase;
|
||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
public class CdtVariableResolverTest extends TestCase {
|
public class CdtVariableResolverTest extends TestCase {
|
||||||
|
private static String acceptedChars = "\\<>&é\"'(§è!çà|@#^¨* []?./+,;:=~)";
|
||||||
|
|
||||||
public static Test suite() {
|
public static Test suite() {
|
||||||
return new TestSuite(CdtVariableResolverTest.class);
|
return new TestSuite(CdtVariableResolverTest.class);
|
||||||
|
@ -35,12 +38,21 @@ public class CdtVariableResolverTest extends TestCase {
|
||||||
if (macroName.equals("null")) {
|
if (macroName.equals("null")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
if (macroName.equals("op")) {
|
||||||
|
return "op";
|
||||||
|
}
|
||||||
|
if (macroName.equals("ro")) {
|
||||||
|
return "ro";
|
||||||
|
}
|
||||||
if (macroName.equals("loop")) {
|
if (macroName.equals("loop")) {
|
||||||
return "${LOOP}";
|
return "${LOOP}";
|
||||||
}
|
}
|
||||||
if (macroName.equals("LOOP")) {
|
if (macroName.equals("LOOP")) {
|
||||||
return "${loop}";
|
return "${loop}";
|
||||||
}
|
}
|
||||||
|
if (macroName.equals(acceptedChars)) {
|
||||||
|
return "OK";
|
||||||
|
}
|
||||||
if (macroName.equals("throw")) {
|
if (macroName.equals("throw")) {
|
||||||
throw new CdtVariableException(ICdtVariableStatus.TYPE_MACRO_UNDEFINED, null, null, null);
|
throw new CdtVariableException(ICdtVariableStatus.TYPE_MACRO_UNDEFINED, null, null, null);
|
||||||
}
|
}
|
||||||
|
@ -64,50 +76,60 @@ public class CdtVariableResolverTest extends TestCase {
|
||||||
|
|
||||||
private MockSubstitutor mockSubstitutor = new MockSubstitutor();
|
private MockSubstitutor mockSubstitutor = new MockSubstitutor();
|
||||||
|
|
||||||
|
//wrapper method to make code easier to read
|
||||||
|
private String resolveToString(String key) throws CdtVariableException {
|
||||||
|
return CdtVariableResolver.resolveToString(key, mockSubstitutor);
|
||||||
|
}
|
||||||
|
|
||||||
public void testResolveToString() throws CdtVariableException {
|
public void testResolveToString() throws CdtVariableException {
|
||||||
|
|
||||||
assertEquals("", CdtVariableResolver.resolveToString(null, mockSubstitutor));
|
assertEquals("", resolveToString(null));
|
||||||
assertEquals("", CdtVariableResolver.resolveToString("", mockSubstitutor));
|
assertEquals("", resolveToString(""));
|
||||||
assertEquals("Text", CdtVariableResolver.resolveToString("Text", mockSubstitutor));
|
assertEquals("Text", resolveToString("Text"));
|
||||||
assertEquals("#Macro#", CdtVariableResolver.resolveToString("${Macro}", mockSubstitutor));
|
assertEquals("#Macro#", resolveToString("${Macro}"));
|
||||||
assertEquals("", CdtVariableResolver.resolveToString("${}", mockSubstitutor));
|
assertEquals("", resolveToString("${}"));
|
||||||
assertEquals("${Nomacro", CdtVariableResolver.resolveToString("${Nomacro", mockSubstitutor));
|
assertEquals("${Nomacro", resolveToString("${Nomacro"));
|
||||||
assertEquals("Nomacro}", CdtVariableResolver.resolveToString("Nomacro}", mockSubstitutor));
|
assertEquals("Nomacro}", resolveToString("Nomacro}"));
|
||||||
assertEquals("Text/#Macro#", CdtVariableResolver.resolveToString("Text/${Macro}", mockSubstitutor));
|
assertEquals("Text/#Macro#", resolveToString("Text/${Macro}"));
|
||||||
assertEquals("#Macro#/Text", CdtVariableResolver.resolveToString("${Macro}/Text", mockSubstitutor));
|
assertEquals("#Macro#/Text", resolveToString("${Macro}/Text"));
|
||||||
assertEquals("#Macro1#/#Macro2#", CdtVariableResolver.resolveToString("${Macro1}/${Macro2}", mockSubstitutor));
|
assertEquals("#Macro1#/#Macro2#", resolveToString("${Macro1}/${Macro2}"));
|
||||||
assertEquals("${Macro}", CdtVariableResolver.resolveToString("\\${Macro}", mockSubstitutor));
|
assertEquals("#=Macro#", resolveToString("${=Macro}"));
|
||||||
assertEquals("${Macro}:#Macro#", CdtVariableResolver.resolveToString("\\${Macro}:${Macro}", mockSubstitutor));
|
assertEquals("#=Macro#:#Macro#", resolveToString("${=Macro}:${Macro}"));
|
||||||
assertEquals("\\#Macro#", CdtVariableResolver.resolveToString("\\\\${Macro}", mockSubstitutor));
|
assertEquals("\\#Macro#", resolveToString("\\${Macro}"));
|
||||||
assertEquals("\\${Macro}", CdtVariableResolver.resolveToString("\\\\\\${Macro}", mockSubstitutor));
|
assertEquals("\\#=Macro#", resolveToString("\\${=Macro}"));
|
||||||
assertEquals("C:\\tmp\\", CdtVariableResolver.resolveToString("C:\\tmp\\", mockSubstitutor));
|
assertEquals("Text/#=Macro#", resolveToString("Text/${=Macro}"));
|
||||||
|
assertEquals("Text/#=Macro#text", resolveToString("Text/${=Macro}text"));
|
||||||
|
assertEquals("Text/#Macro#text", resolveToString("Text/${Macro}text"));
|
||||||
|
assertEquals("Text/#Macro#text", resolveToString("Text/${Mac${ro}}text"));
|
||||||
|
assertEquals("C:\\tmp\\", resolveToString("C:\\tmp\\"));
|
||||||
|
assertEquals("OK", resolveToString("${" + acceptedChars + "}"));
|
||||||
|
//resolve should only resolve 1 level deep
|
||||||
|
assertNotEquals(resolveToString("${LOOP}"), resolveToString(resolveToString("${LOOP}")));
|
||||||
|
|
||||||
assertEquals("#workspace_loc:#Macro##",
|
assertEquals("#workspace_loc:#Macro##", resolveToString("${workspace_loc:${Macro}}"));
|
||||||
CdtVariableResolver.resolveToString("${workspace_loc:${Macro}}", mockSubstitutor));
|
assertEquals("#workspace_loc:#Macro1#/#Macro2##", resolveToString("${workspace_loc:${Macro1}/${Macro2}}"));
|
||||||
assertEquals("#workspace_loc:#Macro1#/#Macro2##",
|
|
||||||
CdtVariableResolver.resolveToString("${workspace_loc:${Macro1}/${Macro2}}", mockSubstitutor));
|
|
||||||
assertEquals("#workspace_loc:#project_loc:/#Macro###",
|
assertEquals("#workspace_loc:#project_loc:/#Macro###",
|
||||||
CdtVariableResolver.resolveToString("${workspace_loc:${project_loc:/${Macro}}}", mockSubstitutor));
|
resolveToString("${workspace_loc:${project_loc:/${Macro}}}"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testExceptions() throws CdtVariableException {
|
public void testExceptions() throws CdtVariableException {
|
||||||
// test exceptions
|
// test exceptions
|
||||||
try {
|
try {
|
||||||
assertEquals("Unreacheable", CdtVariableResolver.resolveToString("${null}", mockSubstitutor));
|
assertEquals("Unreacheable", resolveToString("${null}"));
|
||||||
fail("Exception expected");
|
fail("Exception expected");
|
||||||
} catch (CdtVariableException e) {
|
} catch (CdtVariableException e) {
|
||||||
// expected behavior
|
// expected behavior
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
assertEquals("Unreacheable", CdtVariableResolver.resolveToString("${throw}", mockSubstitutor));
|
assertEquals("Unreacheable", resolveToString("${throw}"));
|
||||||
fail("Exception expected");
|
fail("Exception expected");
|
||||||
} catch (CdtVariableException e) {
|
} catch (CdtVariableException e) {
|
||||||
// expected behavior
|
// expected behavior
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure there is no infinite loop
|
// make sure there is no infinite loop
|
||||||
assertEquals("${LOOP}", CdtVariableResolver.resolveToString("${loop}", mockSubstitutor));
|
assertEquals("${LOOP}", resolveToString("${loop}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testAsList() throws CdtVariableException {
|
public void testAsList() throws CdtVariableException {
|
||||||
|
|
|
@ -62,17 +62,10 @@ public class CdtVariableResolver {
|
||||||
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
|
private static final String EMPTY_STRING = ""; //$NON-NLS-1$
|
||||||
|
|
||||||
public static final String VARIABLE_PREFIX = "${"; //$NON-NLS-1$
|
public static final String VARIABLE_PREFIX = "${"; //$NON-NLS-1$
|
||||||
private static final String VARIABLE_PREFIX_MASKED = "$\1"; //$NON-NLS-1$
|
|
||||||
public static final char VARIABLE_SUFFIX = '}';
|
public static final char VARIABLE_SUFFIX = '}';
|
||||||
private static final char VARIABLE_SUFFIX_MASKED = '\2';
|
|
||||||
public static final char VARIABLE_ESCAPE_CHAR = '\\';
|
|
||||||
private static final char VARIABLE_ESCAPE_CHAR_MASKED = '\3';
|
|
||||||
|
|
||||||
// Regular expression fragments
|
|
||||||
private static final String RE_VPREFIX = "\\$\\{"; //$NON-NLS-1$
|
private static final String RE_VPREFIX = "\\$\\{"; //$NON-NLS-1$
|
||||||
private static final String RE_VSUFFIX = "\\}"; //$NON-NLS-1$
|
private static final String RE_VSUFFIX = "\\}"; //$NON-NLS-1$
|
||||||
private static final String RE_VNAME = "[^${}]*"; //$NON-NLS-1$
|
private static final String RE_VNAME = "[^${}]*"; //$NON-NLS-1$
|
||||||
private static final String RE_BSLASH = "[\\\\]"; // *one* backslash //$NON-NLS-1$
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts list of strings to one string using given string as delimiter,
|
* Converts list of strings to one string using given string as delimiter,
|
||||||
|
@ -99,8 +92,9 @@ public class CdtVariableResolver {
|
||||||
/**
|
/**
|
||||||
* Resolves macros of kind ${Macro} in the given string by calling the macro substitutor
|
* Resolves macros of kind ${Macro} in the given string by calling the macro substitutor
|
||||||
* for each macro reference found. Macros can be inside one another like
|
* for each macro reference found. Macros can be inside one another like
|
||||||
* ${workspace_loc:/${ProjName}/} but resolved just once. No recursive or concatenated
|
* ${workspace_loc:/${ProjName}/} but resolved just once. No recursive
|
||||||
* macro names are allowed. It is possible to prevent macro from expanding using backslash \$.
|
* macro names are allowed.
|
||||||
|
* It is not possible to prevent macros from expanding.
|
||||||
*
|
*
|
||||||
* @param string - macro expression.
|
* @param string - macro expression.
|
||||||
* @param substitutor - macro resolution provider to retrieve macro values.
|
* @param substitutor - macro resolution provider to retrieve macro values.
|
||||||
|
@ -113,43 +107,35 @@ public class CdtVariableResolver {
|
||||||
return EMPTY_STRING;
|
return EMPTY_STRING;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Pattern pattern = Pattern
|
final Pattern pattern = Pattern.compile("(\\$\\{([^${}]*)\\})"); //$NON-NLS-1$
|
||||||
.compile(".*?(" + RE_BSLASH + "*)(" + RE_VPREFIX + "(" + RE_VNAME + ")" + RE_VSUFFIX + ").*"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
|
final String VARIABLE_PREFIX_MASKED = "$\1"; //$NON-NLS-1$
|
||||||
|
final char VARIABLE_SUFFIX_MASKED = '\2';
|
||||||
|
|
||||||
StringBuilder buffer = new StringBuilder(string);
|
StringBuilder buffer = new StringBuilder(string);
|
||||||
int limit = string.length();
|
int limit = string.length();
|
||||||
for (Matcher matcher = pattern.matcher(buffer); matcher.matches(); matcher = pattern.matcher(buffer)) {
|
Matcher matcher = pattern.matcher(buffer);
|
||||||
String bSlashes = matcher.group(1);
|
while (matcher.find()) {
|
||||||
String macro = matcher.group(2);
|
String name = matcher.group(2);
|
||||||
String name = matcher.group(3);
|
|
||||||
String resolved = name.length() > 0 ? substitutor.resolveToString(name) : EMPTY_STRING;
|
String resolved = name.length() > 0 ? substitutor.resolveToString(name) : EMPTY_STRING;
|
||||||
if (resolved == null) {
|
if (resolved == null) {
|
||||||
throw new CdtVariableException(ICdtVariableStatus.TYPE_MACRO_UNDEFINED, null, string, name);
|
throw new CdtVariableException(ICdtVariableStatus.TYPE_MACRO_UNDEFINED, null, string, name);
|
||||||
}
|
}
|
||||||
if (limit-- < 0) {
|
|
||||||
// to prevent incidental looping
|
|
||||||
throw new CdtVariableException(ICdtVariableStatus.TYPE_ERROR, name, matcher.group(0), resolved);
|
|
||||||
}
|
|
||||||
|
|
||||||
int nBSlashes = bSlashes.length();
|
if (limit-- < 0) {
|
||||||
if ((nBSlashes & 1) == 1) {
|
// to prevent incidental endless looping
|
||||||
// if odd number of backslashes in front of "${...}" do not expand macro
|
throw new CdtVariableException(ICdtVariableStatus.TYPE_ERROR, name, string, resolved);
|
||||||
resolved = macro;
|
|
||||||
}
|
}
|
||||||
// Only one expansion is allowed, so hide any text interfering with macro syntax
|
// Only one expansion is allowed, so hide any text interfering with macro syntax
|
||||||
resolved = resolved.replace(VARIABLE_PREFIX, VARIABLE_PREFIX_MASKED);
|
resolved = resolved.replace(VARIABLE_PREFIX, VARIABLE_PREFIX_MASKED);
|
||||||
resolved = resolved.replace(VARIABLE_SUFFIX, VARIABLE_SUFFIX_MASKED);
|
resolved = resolved.replace(VARIABLE_SUFFIX, VARIABLE_SUFFIX_MASKED);
|
||||||
buffer.replace(matcher.start(2), matcher.end(2), resolved);
|
|
||||||
// collapse and hide backslashes \\\\${Macro} -> \\MacroValue or \\\\\${Macro} -> \\${Macro}
|
buffer.replace(matcher.start(1), matcher.end(1), resolved);
|
||||||
buffer.replace(matcher.start(1), matcher.end(1),
|
matcher = pattern.matcher(buffer);
|
||||||
bSlashes.substring(0, nBSlashes / 2).replace(VARIABLE_ESCAPE_CHAR, VARIABLE_ESCAPE_CHAR_MASKED));
|
|
||||||
}
|
}
|
||||||
String result = buffer.toString();
|
String result = buffer.toString();
|
||||||
|
|
||||||
// take hidden data back
|
// take hidden data back
|
||||||
result = result.replace(VARIABLE_PREFIX_MASKED, VARIABLE_PREFIX);
|
result = result.replace(VARIABLE_PREFIX_MASKED, VARIABLE_PREFIX);
|
||||||
result = result.replace(VARIABLE_SUFFIX_MASKED, VARIABLE_SUFFIX);
|
result = result.replace(VARIABLE_SUFFIX_MASKED, VARIABLE_SUFFIX);
|
||||||
result = result.replace(VARIABLE_ESCAPE_CHAR_MASKED, VARIABLE_ESCAPE_CHAR);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue