Skip to content

Commit cf6aa16

Browse files
authored
Merge pull request SonarOpenCommunity#2393 from guwirth/pp-refactoring-9
preprocessor refactoring
2 parents 558a6c2 + 72266d0 commit cf6aa16

File tree

9 files changed

+73
-62
lines changed

9 files changed

+73
-62
lines changed

cxx-sensors/src/main/java/org/sonar/cxx/sensors/coverage/ctc/TestwellCtcTxtResult.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public enum TestwellCtcTxtResult {
5050
Pattern.MULTILINE);
5151
public static final Pattern SECTION_SEP = Pattern.compile("^(-{77}|={77})$", Pattern.MULTILINE);
5252
public static final Pattern LINE_RESULT = Pattern.compile(
53-
"^(?: {10}| *([0-9Ee]+)) (?: {10}| *([0-9Ee]+)) -? *([0-9Ee]+) *(?:}([+-]+))?(.*)$",
53+
"^(?:[ ]{10}|[ ]{0,9}([0-9Ee]{1,9}))[ ](?:[ ]{10}|[ ]{0,9}([0-9Ee]{1,9}))[ ]-?[ ]{0,9}([0-9Ee]{1,9})[ ]{0,256}(?:}([+-]+))?(.{0,256})$",
5454
Pattern.MULTILINE);
5555
public static final Pattern FILE_RESULT = Pattern.compile(
5656
String.join("\\s+", FILE_COND.patternString, FILE_STMT.patternString),

cxx-squid/src/main/java/org/sonar/cxx/channels/PreprocessorChannel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public PreprocessorChannel(TokenType[]... keywordSets) {
4646
for (var keyword : keywords) {
4747
regexp.append("|");
4848
regexp.append(keyword.getValue());
49-
regexp.append("\\s");
49+
regexp.append("\\s++");
5050
}
5151
}
5252
matcher = Pattern.compile(regexp.toString()).matcher("");

cxx-squid/src/main/java/org/sonar/cxx/config/MsBuild.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public void parse(File buildLog, String baseDir, String encodingName) {
167167
// match "bin\CL.exe", "bin\amd64\CL.exe", "bin\x86_amd64\CL.exe"
168168
if (PATH_TO_CL_PATTERN.matcher(line).matches()) {
169169
detectedPlatform = setPlatformToolsetFromLine(line);
170-
String[] allElems = line.split("\\s+");
170+
String[] allElems = line.split("\\s++");
171171
String data = allElems[allElems.length - 1];
172172
parseCLParameters(line, currentProjectPath, data);
173173
LOG.debug("build log parser cl.exe line='{}'", line);

cxx-squid/src/main/java/org/sonar/cxx/parser/CxxLexerPool.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public static CxxLexerPool create(Charset charset, Preprocessor... preprocessors
7979
lexer.builder = Lexer.builder()
8080
.withCharset(charset)
8181
.withFailIfNoChannelToConsumeOneCharacter(true)
82-
.withChannel(new BlackHoleChannel("\\s"))
82+
.withChannel(new BlackHoleChannel("\\s++"))
8383
// C++ Standard, Section 2.8 "Comments"
8484
.withChannel(commentRegexp("//[^\\n\\r]*+"))
8585
.withChannel(commentRegexp("/\\*", ANY_CHAR + "*?", "\\*/"))

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

Lines changed: 51 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import java.nio.charset.Charset;
3333
import java.util.ArrayList;
3434
import java.util.Collections;
35-
import java.util.LinkedList;
3635
import java.util.List;
3736
import java.util.Optional;
3837
import javax.annotation.CheckForNull;
@@ -196,7 +195,10 @@ public PreprocessorAction process(List<Token> tokens) {
196195
} else if (state().skipTokens() && !GenericTokenType.EOF.equals(type)) {
197196
return oneConsumedToken(token);
198197
} else if (GenericTokenType.IDENTIFIER.equals(type) || (type instanceof CxxKeyword)) {
199-
return handleMacroReplacement(tokens);
198+
PPMacro macro = getMacro(token.getValue());
199+
if (macro != null) {
200+
return macroReplacement(macro, tokens);
201+
}
200202
}
201203

202204
return PreprocessorAction.NO_OPERATION;
@@ -557,70 +559,71 @@ private PreprocessorAction handleModuleLine(AstNode ast, Token token) {
557559
* Every identifier and every keyword can be a macro instance. Pipe the resulting string through a lexer to create
558560
* proper tokens and to expand recursively all macros which may be in there.
559561
*/
560-
private PreprocessorAction handleMacroReplacement(List<Token> tokens) {
562+
private PreprocessorAction macroReplacement(PPMacro macro, List<Token> tokens) {
561563
var action = PreprocessorAction.NO_OPERATION;
562564
var firstToken = tokens.get(0);
563-
var macro = getMacro(firstToken.getValue());
564-
if (macro != null) {
565-
var totalTokensConsumed = 0;
566-
List<Token> result;
567-
568-
if (macro.parameterList == null) {
569-
totalTokensConsumed = 1;
570-
result = new LinkedList<>(replace.replaceObjectLikeMacro(
571-
macro, TokenUtils.merge(PPConcatenation.concatenate(macro.replacementList)))
572-
);
573-
} else {
574-
result = new LinkedList<>();
575-
int argsTokensConsumed = replace.replaceFunctionLikeMacro(
576-
macro, tokens.subList(1, tokens.size()), result);
577-
if (argsTokensConsumed > 0) {
578-
totalTokensConsumed = 1 + argsTokensConsumed;
579-
}
565+
var consumedTokens = 0;
566+
List<Token> result;
567+
568+
if (macro.isFunctionLikeMacro()) {
569+
result = new ArrayList<>();
570+
int consumedArgTokens = replace.replaceFunctionLikeMacro(
571+
macro, tokens.subList(1, tokens.size()), result);
572+
if (consumedArgTokens > 0) {
573+
consumedTokens = 1 + consumedArgTokens;
580574
}
575+
} else {
576+
consumedTokens = 1;
577+
result = replace.replaceObjectLikeMacro(
578+
macro, TokenUtils.merge(PPConcatenation.concatenate(macro.replacementList))
579+
);
580+
}
581581

582-
if (totalTokensConsumed > 0) {
583-
// Rescanning to expand function like macros, in case it requires consuming more tokens
584-
unitMacros.pushDisable(macro.identifier);
585-
List<Token> rescanningResult = new LinkedList<>();
586-
totalTokensConsumed = rescanning(result, tokens, totalTokensConsumed, rescanningResult);
587-
unitMacros.popDisable();
588-
589-
result = TokenList.adjustPosition(rescanningResult, firstToken);
590-
action = new PreprocessorAction(
591-
totalTokensConsumed,
592-
Collections.singletonList(Trivia.createSkippedText(tokens.subList(0, totalTokensConsumed))),
593-
result);
594-
}
582+
if (consumedTokens > 0) {
583+
// Rescanning to expand function like macros, in case it requires consuming more tokens
584+
unitMacros.pushDisable(macro.identifier);
585+
List<Token> rescanningResult = new ArrayList<>();
586+
consumedTokens = macroRescanning(result, tokens, consumedTokens, rescanningResult);
587+
unitMacros.popDisable();
588+
589+
result = TokenList.adjustPosition(rescanningResult, firstToken);
590+
action = new PreprocessorAction(
591+
consumedTokens,
592+
Collections.singletonList(Trivia.createSkippedText(tokens.subList(0, consumedTokens))),
593+
result);
595594
}
596595

597596
return action;
598597
}
599598

600-
private int rescanning(List<Token> input, List<Token> tokens, int tokensConsumed, List<Token> output) {
601-
while (!input.isEmpty()) {
602-
var firstToken = input.get(0);
599+
private int macroRescanning(List<Token> input, List<Token> tokens, int consumedTokens, List<Token> output) {
600+
List<Token> view = input;
601+
while (!view.isEmpty()) {
602+
var firstToken = view.get(0);
603603
var action = PreprocessorAction.NO_OPERATION;
604-
if (firstToken.getType().equals(GenericTokenType.IDENTIFIER)) {
605-
List<Token> rest = new ArrayList<>(input);
606-
rest.addAll(tokens.subList(tokensConsumed, tokens.size()));
607-
action = handleMacroReplacement(rest);
604+
if (GenericTokenType.IDENTIFIER.equals(firstToken.getType())) {
605+
PPMacro macro = getMacro(firstToken.getValue());
606+
if (macro != null) {
607+
List<Token> rest = new ArrayList<>(view);
608+
rest.addAll(tokens.subList(consumedTokens, tokens.size()));
609+
action = macroReplacement(macro, rest);
610+
}
608611
}
609-
if (action.equals(PreprocessorAction.NO_OPERATION)) {
610-
input.remove(0);
612+
if (PreprocessorAction.NO_OPERATION.equals(action)) {
613+
view = view.subList(1, view.size()); // next tokens
611614
output.add(firstToken);
612615
} else {
613616
output.addAll(action.getTokensToInject());
614-
int tokensConsumedRescanning = action.getNumberOfConsumedTokens();
615-
if (tokensConsumedRescanning >= input.size()) {
616-
tokensConsumed += tokensConsumedRescanning - input.size();
617-
input.clear();
617+
int consumedRescanningTokens = action.getNumberOfConsumedTokens();
618+
if (consumedRescanningTokens >= view.size()) {
619+
consumedTokens += consumedRescanningTokens - view.size();
620+
view = view.subList(view.size(), view.size()); // was last token
618621
} else {
619-
input.subList(0, tokensConsumedRescanning).clear();
622+
view = view.subList(consumedRescanningTokens, view.size()); // next tokens
620623
}
621624
}
622625
}
623-
return tokensConsumed;
626+
return consumedTokens;
624627
}
625628

626629
private static PreprocessorAction oneConsumedToken(Token token) {

cxx-squid/src/main/java/org/sonar/cxx/preprocessor/IncludeDirectiveLexer.java renamed to cxx-squid/src/main/java/org/sonar/cxx/preprocessor/IncludeFileLexer.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@
2727
import org.sonar.cxx.channels.PreprocessorChannel;
2828
import org.sonar.cxx.config.CxxSquidConfiguration;
2929

30-
final class IncludeDirectiveLexer {
30+
/**
31+
* Included files have to be scanned with the (only) goal of gathering macros. Process include files using
32+
* a special lexer, which calls back only if it finds relevant preprocessor directives (#...).
33+
*/
34+
final class IncludeFileLexer {
3135

32-
private IncludeDirectiveLexer() {
36+
private IncludeFileLexer() {
3337
}
3438

3539
static Lexer create(Preprocessor... preprocessors) {
@@ -40,10 +44,10 @@ static Lexer create(CxxSquidConfiguration squidConfig, Preprocessor... preproces
4044
var builder = Lexer.builder()
4145
.withCharset(squidConfig.getCharset())
4246
.withFailIfNoChannelToConsumeOneCharacter(true)
43-
.withChannel(new BlackHoleChannel("\\s"))
47+
.withChannel(new BlackHoleChannel("\\s++"))
4448
.withChannel(new PreprocessorChannel())
4549
.withChannel(commentRegexp("/\\*", ANY_CHAR + "*?", "\\*/"))
46-
.withChannel(new BlackHoleChannel(".*"));
50+
.withChannel(new BlackHoleChannel(".*+"));
4751

4852
for (var preprocessor : preprocessors) {
4953
builder.withPreprocessor(preprocessor);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class PPInclude {
6666

6767
public PPInclude(CxxPreprocessor pp, @Nonnull File contextFile) {
6868
this.pp = pp;
69-
fileLexer = IncludeDirectiveLexer.create(pp);
69+
fileLexer = IncludeFileLexer.create(pp);
7070
state = PPState.build(contextFile);
7171
}
7272

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,18 @@ static PPMacro create(String source) {
9090
* ...). Otherwise the program is ill-formed.
9191
*/
9292
boolean checkArgumentsCount(int count) {
93-
if (parameterList != null) {
93+
if (isFunctionLikeMacro()) {
9494
return isVariadic ? count >= parameterList.size() - 1 : count == parameterList.size();
9595
}
9696
return false;
9797
}
9898

99+
boolean isFunctionLikeMacro() {
100+
return parameterList != null;
101+
}
102+
99103
int getParameterIndex(String parameterName) {
100-
if (parameterList != null) {
104+
if (isFunctionLikeMacro()) {
101105
for (int i = 0; i < parameterList.size(); i++) {
102106
if (parameterList.get(i).getValue().equals(parameterName)) {
103107
return i;
@@ -112,7 +116,7 @@ public String toString() {
112116
StringBuilder ab = new StringBuilder(64);
113117
ab.append("{");
114118
ab.append(identifier);
115-
if (parameterList != null) {
119+
if (isFunctionLikeMacro()) {
116120
ab.append("(");
117121
ab.append(parameterList.stream().map(Token::getValue).collect(Collectors.joining(", ")));
118122
if (isVariadic) {

cxx-squid/src/test/java/org/sonar/cxx/preprocessor/IncludeDirectiveLexerTest.java renamed to cxx-squid/src/test/java/org/sonar/cxx/preprocessor/IncludeFileLexerTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828
import org.junit.jupiter.api.Test;
2929
import org.sonar.cxx.parser.CxxTokenType;
3030

31-
class IncludeDirectiveLexerTest {
31+
class IncludeFileLexerTest {
3232

33-
private final static Lexer LEXER = IncludeDirectiveLexer.create();
33+
private final static Lexer LEXER = IncludeFileLexer.create();
3434

3535
@Test
3636
void proper_preprocessor_directives_are_created() {

0 commit comments

Comments
 (0)