Skip to content

Commit c7af36e

Browse files
authored
Merge pull request #1637 from ivangalkin/preprocessor_macros
CxxPreprocessor: reduce run-time overhead, extract invariants
2 parents 717aaf2 + 638cd06 commit c7af36e

File tree

5 files changed

+203
-180
lines changed

5 files changed

+203
-180
lines changed

cxx-squid/src/main/java/org/sonar/cxx/CxxCompilationUnitSettings.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@
2020
package org.sonar.cxx;
2121

2222
import java.util.ArrayList;
23+
import java.util.HashMap;
2324
import java.util.List;
2425
import java.util.Map;
25-
import java.util.concurrent.ConcurrentHashMap;
2626
import javax.annotation.Nullable;
2727

2828
/**
2929
* CxxCompilationUnitSettings
3030
*/
3131
public class CxxCompilationUnitSettings {
3232

33-
private Map<String, String> defines = new ConcurrentHashMap<>();
33+
private Map<String, String> defines = new HashMap<>();
3434
private List<String> includes = new ArrayList<>();
3535

3636
public Map<String, String> getDefines() {

cxx-squid/src/main/java/org/sonar/cxx/preprocessor/CxxPreprocessor.java

Lines changed: 17 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import java.util.Collection;
4545
import java.util.Collections;
4646
import java.util.Deque;
47-
import java.util.HashMap;
4847
import java.util.HashSet;
4948
import java.util.Iterator;
5049
import java.util.LinkedList;
@@ -96,15 +95,15 @@ public class CxxPreprocessor extends Preprocessor {
9695
private File currentContextFile;
9796
private String rootFilePath;
9897

99-
private Parser<Grammar> pplineParser;
98+
private final Parser<Grammar> pplineParser;
10099
private final MapChain<String, Macro> fixedMacros = new MapChain<>();
101100
private MapChain<String, Macro> unitMacros;
102101
private final Set<File> analysedFiles = new HashSet<>();
103-
private SourceCodeProvider codeProvider = new SourceCodeProvider();
102+
private final SourceCodeProvider codeProvider;
104103
private SourceCodeProvider unitCodeProvider;
105-
private SquidAstVisitorContext<Grammar> context;
106-
private List<String> cFilesPatterns;
107-
private CxxConfiguration conf;
104+
private final SquidAstVisitorContext<Grammar> context;
105+
private final List<String> cFilesPatterns;
106+
private final CxxConfiguration conf;
108107
private CxxCompilationUnitSettings compilationUnitSettings;
109108
private final Multimap<String, Include> includedFiles = HashMultimap.create();
110109
private final Multimap<String, Include> missingIncludeFiles = HashMultimap.create();
@@ -125,7 +124,7 @@ public CxxPreprocessor(SquidAstVisitorContext<Grammar> context,
125124
SourceCodeProvider sourceCodeProvider,
126125
CxxLanguage language) {
127126
this.context = context;
128-
this.cFilesPatterns = conf.getCFilesPatterns();
127+
this.cFilesPatterns = conf.getCFilesPatterns().stream().map(s -> s.replace("*", "")).collect(Collectors.toList());
129128
this.conf = conf;
130129
this.language = language;
131130

@@ -148,7 +147,7 @@ public CxxPreprocessor(SquidAstVisitorContext<Grammar> context,
148147
}
149148

150149
// set standard macros
151-
registerMacros(StandardDefinitions.macros());
150+
getMacros().putAll(Macro.STANDARD_MACROS);
152151

153152
// parse the configured force includes and store into the macro library
154153
for (String include : conf.getForceIncludeFiles()) {
@@ -499,12 +498,7 @@ public PreprocessorAction process(List<Token> tokens) { //TODO: deprecated Prepr
499498

500499
// set standard macros
501500
// using smaller set of defines as rest is provides by compilation unit settings
502-
HashMap<String, String> defines = new HashMap<>();
503-
defines.put("__FILE__", "\"file\"");
504-
defines.put("__LINE__", "1");
505-
defines.put("__DATE__", "\"??? ?? ????\"");
506-
defines.put("__TIME__", "\"??:??:??\"");
507-
registerMacros(defines);
501+
getMacros().putAll(Macro.UNIT_MACROS);
508502

509503
// parse the configured force includes and store into the macro library
510504
for (String include : conf.getForceIncludeFiles()) {
@@ -516,21 +510,25 @@ public PreprocessorAction process(List<Token> tokens) { //TODO: deprecated Prepr
516510
}
517511

518512
// rest of defines comes from compilation unit settings
519-
registerMacros(compilationUnitSettings.getDefines());
513+
for (Map.Entry<String, String> entry : compilationUnitSettings.getDefines().entrySet()) {
514+
final String name = entry.getKey();
515+
final String body = entry.getValue();
516+
getMacros().put(name, new Macro(name, body));
517+
}
520518
} finally {
521519
getMacros().setHighPrio(false);
522520
}
523521

524522
if (getMacro(CPLUSPLUS) == null) {
525523
//Create macros to replace C++ keywords when parsing C files
526-
registerMacros(StandardDefinitions.compatibilityMacros());
524+
getMacros().putAll(Macro.COMPATIBILITY_MACROS);
527525
}
528526
} else {
529527
// Use global settings
530528
LOG.debug("global settings for: '{}'", rootFilePath);
531529
if (isCFile(currentContextFile.getAbsolutePath())) {
532530
//Create macros to replace C++ keywords when parsing C files
533-
registerMacros(StandardDefinitions.compatibilityMacros());
531+
getMacros().putAll(Macro.COMPATIBILITY_MACROS);
534532
fixedMacros.disable(CPLUSPLUS);
535533
} else {
536534
fixedMacros.enable(CPLUSPLUS);
@@ -647,29 +645,9 @@ public Boolean expandHasIncludeExpression(AstNode exprAst) {
647645
return findIncludedFile(exprAst, exprAst.getToken(), filePath) != null;
648646
}
649647

650-
private void registerMacros(Map<String, String> standardMacros) {
651-
for (Map.Entry<String, String> entry : standardMacros.entrySet()) {
652-
Token bodyToken;
653-
try {
654-
bodyToken = Token.builder()
655-
.setLine(1)
656-
.setColumn(0)
657-
.setURI(new java.net.URI(""))
658-
.setValueAndOriginalValue(entry.getValue())
659-
.setType(STRING)
660-
.build();
661-
} catch (java.net.URISyntaxException e) {
662-
throw new PreprocessorRuntimeException("URI cannot be handled", e);
663-
}
664-
665-
getMacros().put(entry.getKey(), new Macro(entry.getKey(), null, Collections.singletonList(bodyToken), false));
666-
}
667-
}
668-
669648
private boolean isCFile(String filePath) {
670649
for (String pattern : cFilesPatterns) {
671-
String patt = pattern.replace("*", "");
672-
if (filePath.endsWith(patt)) {
650+
if (filePath.endsWith(pattern)) {
673651
LOG.debug("Parse '{}' as C file, ends in '{}'", filePath, pattern);
674652
return true;
675653
}
@@ -1102,8 +1080,7 @@ PreprocessorAction handleIncludeLine(AstNode ast, Token token, String filename,
11021080
if (currentFile != null) {
11031081
missingIncludeFiles.put(currentFile.getPath(), new Include(token.getLine(), token.getValue()));
11041082
}
1105-
} else if (!analysedFiles.contains(includedFile)) {
1106-
analysedFiles.add(includedFile.getAbsoluteFile());
1083+
} else if (analysedFiles.add(includedFile.getAbsoluteFile())) {
11071084
if (LOG.isTraceEnabled()) {
11081085
LOG.trace("[{}:{}]: processing {}, resolved to file '{}'",
11091086
filename, token.getLine(), token.getValue(), includedFile.getAbsolutePath());
@@ -1295,42 +1272,6 @@ static class MismatchException extends Exception {
12951272
}
12961273
}
12971274

1298-
static final class Macro {
1299-
1300-
private final String name;
1301-
private final List<Token> params;
1302-
private final List<Token> body;
1303-
private final boolean isVariadic;
1304-
1305-
public Macro(String name, @Nullable List<Token> params, @Nullable List<Token> body, boolean variadic) {
1306-
this.name = name;
1307-
if (params == null) {
1308-
this.params = null;
1309-
} else {
1310-
this.params = params.stream().collect(Collectors.toList());
1311-
}
1312-
if (body == null) {
1313-
this.body = null;
1314-
} else {
1315-
this.body = body.stream().collect(Collectors.toList());
1316-
}
1317-
this.isVariadic = variadic;
1318-
}
1319-
1320-
@Override
1321-
public String toString() {
1322-
return name
1323-
+ (params == null ? "" : "(" + serialize(params, ", ") + (isVariadic ? "..." : "") + ")")
1324-
+ " -> '" + serialize(body) + "'";
1325-
}
1326-
1327-
public boolean checkArgumentsCount(int count) {
1328-
return isVariadic
1329-
? count >= params.size() - 1
1330-
: count == params.size();
1331-
}
1332-
}
1333-
13341275
static class PreprocessorRuntimeException extends RuntimeException {
13351276

13361277
/**
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
* Sonar C++ Plugin (Community)
3+
* Copyright (C) 2010-2018 SonarOpenCommunity
4+
* http://github.com/SonarOpenCommunity/sonar-cxx
5+
*
6+
* This program is free software; you can redistribute it and/or
7+
* modify it under the terms of the GNU Lesser General Public
8+
* License as published by the Free Software Foundation; either
9+
* version 3 of the License, or (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
* Lesser General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Lesser General Public License
17+
* along with this program; if not, write to the Free Software Foundation,
18+
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
*/
20+
package org.sonar.cxx.preprocessor;
21+
22+
import static org.sonar.cxx.api.CxxTokenType.STRING;
23+
24+
import java.net.URI;
25+
import java.util.ArrayList;
26+
import java.util.Collections;
27+
import java.util.HashMap;
28+
import java.util.List;
29+
import java.util.Map;
30+
import java.util.stream.Collectors;
31+
32+
import javax.annotation.Nullable;
33+
34+
import com.sonar.sslr.api.Token;
35+
36+
public final class Macro {
37+
38+
public final String name;
39+
public final List<Token> params;
40+
public final List<Token> body;
41+
public final boolean isVariadic;
42+
43+
public Macro(String name, @Nullable List<Token> params, @Nullable List<Token> body, boolean variadic) {
44+
this.name = name;
45+
if (params == null) {
46+
this.params = null;
47+
} else {
48+
this.params = new ArrayList<>(params);
49+
}
50+
if (body == null) {
51+
this.body = null;
52+
} else {
53+
this.body = new ArrayList<>(body);
54+
}
55+
this.isVariadic = variadic;
56+
}
57+
58+
/**
59+
* Constructor for standard (predefined) macros
60+
*
61+
* @param name
62+
* @param body
63+
*/
64+
public Macro(String name, String body) {
65+
this.name = name;
66+
this.params = null;
67+
this.body = Collections.singletonList(Token.builder()
68+
.setLine(1)
69+
.setColumn(0)
70+
.setURI(URI.create(""))
71+
.setValueAndOriginalValue(body)
72+
.setType(STRING)
73+
.build());
74+
this.isVariadic = false;
75+
}
76+
77+
@Override
78+
public String toString() {
79+
String paramsStr = "";
80+
if (params != null) {
81+
final String joinedParams = params.stream().map(Token::getValue).collect(Collectors.joining(", "));
82+
paramsStr = "(" + joinedParams + (isVariadic ? "..." : "") + ")";
83+
}
84+
String bodyStr = "";
85+
if (body != null) {
86+
bodyStr = body.stream().map(Token::getValue).collect(Collectors.joining(" "));
87+
}
88+
return name + paramsStr + " -> '" + bodyStr + "'";
89+
}
90+
91+
public boolean checkArgumentsCount(int count) {
92+
return isVariadic ? count >= params.size() - 1 : count == params.size();
93+
}
94+
95+
private static void add(Map<String, Macro> map, String name, String body) {
96+
map.put(name, new Macro(name, body));
97+
}
98+
99+
/**
100+
* This is a collection of standard macros according to
101+
* http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
102+
*/
103+
private static final Map<String, Macro> STANDARD_MACROS_IMPL = new HashMap<>();
104+
static {
105+
106+
add(STANDARD_MACROS_IMPL, "__FILE__", "\"file\"");
107+
add(STANDARD_MACROS_IMPL, "__LINE__", "1");
108+
// indicates 'date unknown'. should suffice
109+
add(STANDARD_MACROS_IMPL, "__DATE__", "\"??? ?? ????\"");
110+
// indicates 'time unknown'. should suffice
111+
add(STANDARD_MACROS_IMPL, "__TIME__", "\"??:??:??\"");
112+
add(STANDARD_MACROS_IMPL, "__STDC__", "1");
113+
add(STANDARD_MACROS_IMPL, "__STDC_HOSTED__", "1");
114+
add(STANDARD_MACROS_IMPL, "__cplusplus", "201103L");
115+
// __has_include support (C++17)
116+
add(STANDARD_MACROS_IMPL, "__has_include", "1");
117+
}
118+
119+
/**
120+
* Smaller set of defines as rest is provides by compilation unit settings
121+
*/
122+
private static final Map<String, Macro> UNIT_MACROS_IMPL = new HashMap<>();
123+
static {
124+
add(UNIT_MACROS_IMPL, "__FILE__", "\"file\"");
125+
add(UNIT_MACROS_IMPL, "__LINE__", "1");
126+
add(UNIT_MACROS_IMPL, "__DATE__", "\"??? ?? ????\"");
127+
add(UNIT_MACROS_IMPL, "__TIME__", "\"??:??:??\"");
128+
}
129+
130+
/**
131+
* Macros to replace C++ keywords when parsing C files
132+
*/
133+
private static Map<String, Macro> COMPATIBILITY_MACROS_IMPL = new HashMap<>();
134+
static {
135+
// This is a collection of macros used to let C code be parsed by C++ parser
136+
add(COMPATIBILITY_MACROS_IMPL, "alignas", "__alignas");
137+
add(COMPATIBILITY_MACROS_IMPL, "alignof", "__alignof");
138+
add(COMPATIBILITY_MACROS_IMPL, "catch", "__catch");
139+
add(COMPATIBILITY_MACROS_IMPL, "class", "__class");
140+
add(COMPATIBILITY_MACROS_IMPL, "constexpr", "__constexpr");
141+
add(COMPATIBILITY_MACROS_IMPL, "const_cast", "__const_cast");
142+
add(COMPATIBILITY_MACROS_IMPL, "decltype", "__decltype");
143+
add(COMPATIBILITY_MACROS_IMPL, "delete", "__delete");
144+
add(COMPATIBILITY_MACROS_IMPL, "dynamic_cast", "__dynamic_cast");
145+
add(COMPATIBILITY_MACROS_IMPL, "explicit", "__explicit");
146+
add(COMPATIBILITY_MACROS_IMPL, "export", "__export");
147+
add(COMPATIBILITY_MACROS_IMPL, "final", "__final");
148+
add(COMPATIBILITY_MACROS_IMPL, "friend", "__friend");
149+
add(COMPATIBILITY_MACROS_IMPL, "mutable", "__mutable");
150+
add(COMPATIBILITY_MACROS_IMPL, "namespace", "__namespace");
151+
add(COMPATIBILITY_MACROS_IMPL, "new", "__new");
152+
add(COMPATIBILITY_MACROS_IMPL, "noexcept", "__noexcept");
153+
add(COMPATIBILITY_MACROS_IMPL, "nullptr", "__nullptr");
154+
add(COMPATIBILITY_MACROS_IMPL, "operator", "__operator");
155+
add(COMPATIBILITY_MACROS_IMPL, "override", "__override");
156+
add(COMPATIBILITY_MACROS_IMPL, "private", "__private");
157+
add(COMPATIBILITY_MACROS_IMPL, "protected", "__protected");
158+
add(COMPATIBILITY_MACROS_IMPL, "public", "__public");
159+
add(COMPATIBILITY_MACROS_IMPL, "reinterpret_cast", "__reinterpret_cast");
160+
add(COMPATIBILITY_MACROS_IMPL, "static_assert", "__static_assert");
161+
add(COMPATIBILITY_MACROS_IMPL, "static_cast", "__static_cast");
162+
add(COMPATIBILITY_MACROS_IMPL, "thread_local", "__thread_local");
163+
add(COMPATIBILITY_MACROS_IMPL, "throw", "__throw");
164+
add(COMPATIBILITY_MACROS_IMPL, "try", "__try");
165+
add(COMPATIBILITY_MACROS_IMPL, "typeid", "__typeid");
166+
add(COMPATIBILITY_MACROS_IMPL, "typename", "__typename");
167+
add(COMPATIBILITY_MACROS_IMPL, "using", "__using");
168+
add(COMPATIBILITY_MACROS_IMPL, "template", "__template");
169+
add(COMPATIBILITY_MACROS_IMPL, "virtual", "__virtual");
170+
}
171+
172+
public static final Map<String, Macro> STANDARD_MACROS = Collections.unmodifiableMap(STANDARD_MACROS_IMPL);
173+
public static final Map<String, Macro> UNIT_MACROS = Collections.unmodifiableMap(UNIT_MACROS_IMPL);
174+
public static final Map<String, Macro> COMPATIBILITY_MACROS = Collections.unmodifiableMap(COMPATIBILITY_MACROS_IMPL);
175+
176+
}

cxx-squid/src/main/java/org/sonar/cxx/preprocessor/MapChain.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ public V put(K key, V value) {
6767
}
6868
}
6969

70+
public void putAll(Map<K, V> m) {
71+
if (isHighPrioEnabled) {
72+
highPrioMap.putAll(m);
73+
} else {
74+
lowPrioMap.putAll(m);
75+
}
76+
}
77+
7078
/**
7179
* removeLowPrio
7280
*

0 commit comments

Comments
 (0)