From 5bc5771a9cbb27ab4f6e046543d677a740fec9b8 Mon Sep 17 00:00:00 2001 From: "L. Sousa" Date: Tue, 4 Aug 2026 17:19:20 +0100 Subject: [PATCH 1/4] perf: skip discarded syntax AST rebuild Keep rebuildAst(true) as the full replacement-tree path, while rebuildAst(false) validates woven sources through clang-dumper without decoding its output into a temporary Clava AST. --- .../fe/specs/clang/codeparser/CodeParser.java | 5 ++ .../clang/codeparser/ParallelCodeParser.java | 56 ++++++++++++++++++ .../fe/specs/clang/dumper/ClangAstDumper.java | 59 ++++++++++++++++++- .../up/fe/specs/clava/weaver/CxxWeaver.java | 55 +++++++++-------- 4 files changed, 149 insertions(+), 26 deletions(-) diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/CodeParser.java b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/CodeParser.java index e65c941a9..475cdd681 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/CodeParser.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/CodeParser.java @@ -63,6 +63,11 @@ public static String getBuiltinOption() { public abstract App parse(List sources, List compilerOptions, ClavaContext context); + /** + * Runs the configured compiler/dumper pipeline without decoding its AST output. + */ + public abstract void validateSyntax(List sources, List compilerOptions, ClavaContext context); + /** * * @param sources diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java index 91b7ca5b9..dd1c20832 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java @@ -293,6 +293,62 @@ public App parse(List inputSources, List compilerOptions, ClavaCon } + @Override + public void validateSyntax(List inputSources, List compilerOptions, ClavaContext context) { + DataStore options = ClangAstKeys.toDataStore(compilerOptions); + options.add(ClavaNode.CONTEXT, context); + + List sources = SpecsIo.getFileMap(inputSources, SourceType.getPermittedExtensions()).keySet().stream() + .map(File::new) + .sorted() + .collect(Collectors.toList()); + + Standard standard = getStandard(sources, options); + ClangResources clangResources = new ClangResources(this); + var clangFiles = clangResources.getClangFiles(get(ClangAstKeys.LIBC_CXX_MODE)); + File validationFolder = SpecsIo.getTempFolder("clava_syntax_validation_" + UUID.randomUUID()); + List errors = new ArrayList<>(); + + try { + int numThreads = get(PARALLEL_PARSING) ? get(PARSING_NUM_THREADS) : 1; + if (numThreads <= 0) { + numThreads = Runtime.getRuntime().availableProcessors(); + } + + ExecutorService executor = Executors.newFixedThreadPool(numThreads); + List> validationResults = new ArrayList<>(); + for (int i = 0; i < sources.size(); i++) { + File source = sources.get(i); + String id = Integer.toString(i + 1); + validationResults.add(executor.submit(() -> validateSource(source, id, standard, options, + validationFolder, clangFiles.clangExecutable(), clangFiles.builtinIncludes()))); + } + executor.shutdown(); + + for (var validationResult : validationResults) { + String error = SpecsSystem.get(validationResult); + if (error != null) { + errors.add(error); + } + } + } finally { + SpecsIo.deleteFolder(validationFolder); + } + + if (!errors.isEmpty() && !get(CONTINUE_ON_PARSING_ERRORS)) { + throw new ClavaParserException(errors, clangFiles); + } + } + + private String validateSource(File source, String id, Standard standard, DataStore options, File validationFolder, + File clangExecutable, List builtinIncludes) { + + var dumper = new ClangAstDumper(false, clangExecutable, builtinIncludes, this) + .setBaseFolder(validationFolder) + .setSystemIncludesThreshold(get(SYSTEM_INCLUDES_THRESHOLD)); + return dumper.validateSyntax(source, id, standard, options) ? null : dumper.getLastValidationError(); + } + // private ClangParserData getParserData(Future future) { // try { // return SpecsSystem.get(future); diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/dumper/ClangAstDumper.java b/ClangAstParser/src/pt/up/fe/specs/clang/dumper/ClangAstDumper.java index de800f155..3f90a5df3 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/dumper/ClangAstDumper.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/dumper/ClangAstDumper.java @@ -41,7 +41,6 @@ import java.io.File; import java.io.InputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Objects; @@ -80,6 +79,8 @@ public static boolean usePlugin() { private File systemResourceDir; private int systemIncludesThreshold; private final ClangResources clangResources; + private boolean validationOnly; + private String lastValidationError; private final CodeParser parserConfig; @@ -138,6 +139,27 @@ public ClangAstData parse(File sourceFile, String id, Standard standard, DataSto return parsePrivate(sourceFile, id, standard, config); } + /** + * Invokes Clang with the same arguments as parsing, while discarding dumper output. + */ + public boolean validateSyntax(File sourceFile, String id, Standard standard, DataStore config) { + if (config.get(ClangAstKeys.USES_CILK)) { + sourceFile = new CilkParser().prepareCilkFile(sourceFile); + } + + validationOnly = true; + try { + parsePrivate(sourceFile, id, standard, config); + return lastValidationError == null; + } finally { + validationOnly = false; + } + } + + public String getLastValidationError() { + return lastValidationError; + } + private ClangAstData parsePrivate(File sourceFile, String id, Standard standard, DataStore config) { ClavaLog.debug(() -> "Data store config for single file parser: " + config); @@ -277,6 +299,11 @@ else if (SourceType.isHeader(sourceFile)) { ClavaLog.debug(() -> "Calling Clang AST Dumper: " + arguments); + if (validationOnly) { + lastValidationError = validateSyntax(arguments, sourceFile, id); + return null; + } + ClangAstData parsedData = null; ProcessOutput output = null; @@ -350,6 +377,36 @@ private void addCudaPathArgument(List arguments, String cudaPath) { } } + private String validateSyntax(List arguments, File sourceFile, String id) { + lastWorkingFolder = SpecsIo.mkdir(baseFolder, sourceFile.getName() + "_" + id); + SpecsIo.deleteFolderContents(lastWorkingFolder); + workingFolders.add(lastWorkingFolder); + + var output = SpecsSystem.runProcess(arguments, lastWorkingFolder, + this::discardOutput, + inputStream -> processOutput(inputStream)); + + output.getOutputException().ifPresent(exception -> { + throw new RuntimeException("Exception while validating syntax", exception); + }); + + if (output.isError()) { + return "Syntax validation failed for '" + sourceFile.getAbsolutePath() + "':\n" + output.getStdErr(); + } + + return null; + } + + private String discardOutput(InputStream inputStream) { + try (LineStream lines = LineStream.newInstance(inputStream, null)) { + while (lines.hasNextLine()) { + lines.nextLine(); + } + } + + return ""; + } + private String processOutput(InputStream inputStream) { StringBuilder output = new StringBuilder(); try (LineStream lines = LineStream.newInstance(inputStream, null)) { diff --git a/ClavaWeaver/src/pt/up/fe/specs/clava/weaver/CxxWeaver.java b/ClavaWeaver/src/pt/up/fe/specs/clava/weaver/CxxWeaver.java index e76857769..47fc313f3 100644 --- a/ClavaWeaver/src/pt/up/fe/specs/clava/weaver/CxxWeaver.java +++ b/ClavaWeaver/src/pt/up/fe/specs/clava/weaver/CxxWeaver.java @@ -575,26 +575,26 @@ public App createApp(List sources, List parserOptions, List "Creating App using the following options: " + parserOptions); ClavaLog.debug(() -> "Creating App using the following extra options: " + extraOptions); - // Collect additional include folders - Set sourceIncludeFolders = getSourceIncludes(sources); - ClavaLog.debug(() -> "Source include folders: " + sourceIncludeFolders); + CodeParser codeParser = newCodeParser(); - // Add include folders to extra options - List adaptedExtraOptions = new ArrayList<>(sourceIncludeFolders.size() + extraOptions.size()); - adaptedExtraOptions.addAll(extraOptions); - sourceIncludeFolders.stream().map(includeFolder -> "-I" + includeFolder).forEach(adaptedExtraOptions::add); + List allParserOptions = addSourceIncludes(sources, parserOptions, extraOptions); + App app = codeParser.parse(sources, allParserOptions, context); - List allFiles = sources.stream().map(File::toString).collect(Collectors.toList()); + // Set source paths of each TranslationUnit + app.setSources(currentBases); + app.setSourceFoldernames(sourceFoldernames); - // Sort filenames so that select order of files is consistent between OSes - Collections.sort(allFiles); + // Set external dependencies + app.getExternalDependencies() + .setDisableRemoteDependencies(this.dataStore.get(ClavaOptions.DISABLE_REMOTE_DEPENDENCIES)); - boolean useCustomResources = this.dataStore.get(ClavaOptions.CUSTOM_RESOURCES); + return app; + } + private CodeParser newCodeParser() { CodeParser codeParser = CodeParser.newInstance(); - // Setup code parser - codeParser.set(CodeParser.USE_CUSTOM_RESOURCES, useCustomResources); + codeParser.set(CodeParser.USE_CUSTOM_RESOURCES, this.dataStore.get(ClavaOptions.CUSTOM_RESOURCES)); codeParser.set(CodeParser.CUDA_GPU_ARCH, this.dataStore.get(CodeParser.CUDA_GPU_ARCH)); codeParser.set(CodeParser.CUDA_PATH, this.dataStore.get(CodeParser.CUDA_PATH)); codeParser.set(ParallelCodeParser.PARALLEL_PARSING, this.dataStore.get(ParallelCodeParser.PARALLEL_PARSING)); @@ -606,20 +606,18 @@ public App createApp(List sources, List parserOptions, List allParserOptions = new ArrayList<>(parserOptions.size() + adaptedExtraOptions.size()); - allParserOptions.addAll(parserOptions); - allParserOptions.addAll(adaptedExtraOptions); - App app = codeParser.parse(SpecsCollections.map(allFiles, File::new), allParserOptions, context); - - // Set source paths of each TranslationUnit - app.setSources(currentBases); - app.setSourceFoldernames(sourceFoldernames); + return codeParser; + } - // Set external dependencies - app.getExternalDependencies() - .setDisableRemoteDependencies(this.dataStore.get(ClavaOptions.DISABLE_REMOTE_DEPENDENCIES)); + private List addSourceIncludes(List sources, List parserOptions, List extraOptions) { + Set sourceIncludeFolders = getSourceIncludes(sources); + ClavaLog.debug(() -> "Source include folders: " + sourceIncludeFolders); - return app; + List allParserOptions = new ArrayList<>(parserOptions.size() + sourceIncludeFolders.size() + extraOptions.size()); + allParserOptions.addAll(parserOptions); + allParserOptions.addAll(extraOptions); + sourceIncludeFolders.stream().map(includeFolder -> "-I" + includeFolder).forEach(allParserOptions::add); + return allParserOptions; } private Set getSourceIncludes(List sources) { @@ -1233,6 +1231,13 @@ public boolean rebuildAst(boolean update) { .forEach(writtenFile -> rebuildBases.put(SpecsIo.getCanonicalFile(writtenFile), tempFolder)); currentBases = rebuildBases; + if (!update) { + newCodeParser().validateSyntax(writtenFiles, + addSourceIncludes(writtenFiles, rebuildOptions, extraOptions), context); + currentBases = previousBases; + return true; + } + App rebuiltApp = createApp(writtenFiles, rebuildOptions, extraOptions); // Restore current bases From 818c49215f542bb7bef9f1e16e6c5facd9a19875 Mon Sep 17 00:00:00 2001 From: "L. Sousa" Date: Fri, 4 Sep 2026 01:16:53 +0100 Subject: [PATCH 2/4] fix: pass system resource dir to syntax validator Update the diagnostics-only ClangAstDumper construction for the rebased constructor signature. --- .../up/fe/specs/clang/codeparser/ParallelCodeParser.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java index dd1c20832..634716d7c 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java @@ -321,7 +321,8 @@ public void validateSyntax(List inputSources, List compilerOptions File source = sources.get(i); String id = Integer.toString(i + 1); validationResults.add(executor.submit(() -> validateSource(source, id, standard, options, - validationFolder, clangFiles.clangExecutable(), clangFiles.builtinIncludes()))); + validationFolder, clangFiles.clangExecutable(), clangFiles.builtinIncludes(), + clangFiles.systemResourceDir()))); } executor.shutdown(); @@ -341,9 +342,9 @@ public void validateSyntax(List inputSources, List compilerOptions } private String validateSource(File source, String id, Standard standard, DataStore options, File validationFolder, - File clangExecutable, List builtinIncludes) { + File clangExecutable, List builtinIncludes, File systemResourceDir) { - var dumper = new ClangAstDumper(false, clangExecutable, builtinIncludes, this) + var dumper = new ClangAstDumper(false, clangExecutable, builtinIncludes, systemResourceDir, this) .setBaseFolder(validationFolder) .setSystemIncludesThreshold(get(SYSTEM_INCLUDES_THRESHOLD)); return dumper.validateSyntax(source, id, standard, options) ? null : dumper.getLastValidationError(); From 0cc7dab01da671449d2fd2e2e6402d0163ba01fe Mon Sep 17 00:00:00 2001 From: "L. Sousa" Date: Sat, 5 Sep 2026 00:36:05 +0100 Subject: [PATCH 3/4] refactor: reuse parse pipeline for syntax validation Replace the parallel validateSyntax orchestration chain (abstract method on CodeParser plus duplicated setup in ParallelCodeParser) with a SYNTAX_ONLY flag consulted by the existing parse() path, so clang arguments, resources, parallelism, and error handling have a single source of truth. ClangAstDumper.validateSyntax now returns the error message directly. --- .../fe/specs/clang/codeparser/CodeParser.java | 5 - .../clang/codeparser/ParallelCodeParser.java | 102 +++++++----------- .../fe/specs/clang/dumper/ClangAstDumper.java | 12 +-- .../up/fe/specs/clava/weaver/CxxWeaver.java | 5 +- 4 files changed, 45 insertions(+), 79 deletions(-) diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/CodeParser.java b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/CodeParser.java index 475cdd681..e65c941a9 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/CodeParser.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/CodeParser.java @@ -63,11 +63,6 @@ public static String getBuiltinOption() { public abstract App parse(List sources, List compilerOptions, ClavaContext context); - /** - * Runs the configured compiler/dumper pipeline without decoding its AST output. - */ - public abstract void validateSyntax(List sources, List compilerOptions, ClavaContext context); - /** * * @param sources diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java index 634716d7c..909624dbc 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java @@ -17,6 +17,7 @@ import org.suikasoft.jOptions.Datakey.KeyFactory; import org.suikasoft.jOptions.Interfaces.DataStore; import pt.up.fe.specs.clang.ClangAstKeys; +import pt.up.fe.specs.clang.ClangFiles; import pt.up.fe.specs.clang.ClangResources; import pt.up.fe.specs.clang.dumper.ClangAstData; import pt.up.fe.specs.clang.dumper.ClangAstDumper; @@ -70,6 +71,9 @@ public class ParallelCodeParser extends CodeParser { public static final DataKey CONTINUE_ON_PARSING_ERRORS = KeyFactory.bool("continueOnParsingErrors") .setLabel("Ignores parsing errors in C/C++ source code"); + public static final DataKey SYNTAX_ONLY = KeyFactory.bool("syntaxOnly") + .setLabel("Runs the compiler/dumper pipeline only to validate syntax, without decoding the AST"); + // public static final DataKey SYSTEM_INCLUDES_THRESHOLD = KeyFactory.integer("systemIncludesThreshold", 1) // .setLabel("Number of threads to use for parallel parsing"); @@ -86,6 +90,9 @@ public App parse(List inputSources, List compilerOptions, ClavaCon Map allSources = SpecsIo.getFileMap(allSourceFolders, SourceType.getPermittedExtensions()); ConcurrentLinkedQueue clangDump = new ConcurrentLinkedQueue<>(); + ConcurrentLinkedQueue syntaxErrors = new ConcurrentLinkedQueue<>(); + + boolean syntaxOnly = get(SYNTAX_ONLY); DataStore options = ClangAstKeys.toDataStore(compilerOptions); @@ -117,7 +124,8 @@ public App parse(List inputSources, List compilerOptions, ClavaCon ClavaLog.info("Found " + sources.size() + " source files"); // ClavaLog.debug(() -> "[ParallelCodeParser] Files to parse:" + sources); - File parsingFolder = SpecsIo.getTempFolder("clava_parsing_" + UUID.randomUUID().toString()); + File parsingFolder = SpecsIo + .getTempFolder((syntaxOnly ? "clava_syntax_validation" : "clava_parsing") + "_" + UUID.randomUUID()); ClavaLog.debug(() -> "Parsing using folder '" + parsingFolder + "'"); // AtomicInteger currentSourceFileIndex = new AtomicInteger(0); @@ -139,8 +147,7 @@ public App parse(List inputSources, List compilerOptions, ClavaCon Future tUnit = executor .submit(() -> parseSource(source, id, standard, options, clangDump, - counter, parsingFolder, clangFiles.clangExecutable(), clangFiles.builtinIncludes(), - clangFiles.systemResourceDir())); + counter, parsingFolder, clangFiles, syntaxErrors)); futureTUnits.add(tUnit); @@ -159,6 +166,10 @@ public App parse(List inputSources, List compilerOptions, ClavaCon var parserData = SpecsSystem.get(future); clangParserResults.add(parserData); } catch (Exception e) { + if (syntaxOnly) { + throw new RuntimeException("Error while validating syntax of file '" + sources.get(i) + "'", e); + } + SpecsLogs.warn("Could not parse file '" + sources.get(i) + "', will be ignored", e); ignoredFiles.add(sources.get(i)); continue; @@ -177,6 +188,16 @@ public App parse(List inputSources, List compilerOptions, ClavaCon // Delete temporary folder SpecsIo.deleteFolder(parsingFolder); + // No AST was decoded, just report syntax validation errors + if (syntaxOnly) { + List validationErrors = new ArrayList<>(syntaxErrors); + if (!validationErrors.isEmpty() && !get(CONTINUE_ON_PARSING_ERRORS)) { + throw new ClavaParserException(validationErrors, clangFiles); + } + + return null; + } + // List tUnits = SpecsCollections.getStream(allSources.keySet(), get(PARALLEL_PARSING)) // .map(sourceFile -> parseSource(new File(sourceFile), standard, options, clangDump, // counter, parsingFolder)) @@ -293,63 +314,6 @@ public App parse(List inputSources, List compilerOptions, ClavaCon } - @Override - public void validateSyntax(List inputSources, List compilerOptions, ClavaContext context) { - DataStore options = ClangAstKeys.toDataStore(compilerOptions); - options.add(ClavaNode.CONTEXT, context); - - List sources = SpecsIo.getFileMap(inputSources, SourceType.getPermittedExtensions()).keySet().stream() - .map(File::new) - .sorted() - .collect(Collectors.toList()); - - Standard standard = getStandard(sources, options); - ClangResources clangResources = new ClangResources(this); - var clangFiles = clangResources.getClangFiles(get(ClangAstKeys.LIBC_CXX_MODE)); - File validationFolder = SpecsIo.getTempFolder("clava_syntax_validation_" + UUID.randomUUID()); - List errors = new ArrayList<>(); - - try { - int numThreads = get(PARALLEL_PARSING) ? get(PARSING_NUM_THREADS) : 1; - if (numThreads <= 0) { - numThreads = Runtime.getRuntime().availableProcessors(); - } - - ExecutorService executor = Executors.newFixedThreadPool(numThreads); - List> validationResults = new ArrayList<>(); - for (int i = 0; i < sources.size(); i++) { - File source = sources.get(i); - String id = Integer.toString(i + 1); - validationResults.add(executor.submit(() -> validateSource(source, id, standard, options, - validationFolder, clangFiles.clangExecutable(), clangFiles.builtinIncludes(), - clangFiles.systemResourceDir()))); - } - executor.shutdown(); - - for (var validationResult : validationResults) { - String error = SpecsSystem.get(validationResult); - if (error != null) { - errors.add(error); - } - } - } finally { - SpecsIo.deleteFolder(validationFolder); - } - - if (!errors.isEmpty() && !get(CONTINUE_ON_PARSING_ERRORS)) { - throw new ClavaParserException(errors, clangFiles); - } - } - - private String validateSource(File source, String id, Standard standard, DataStore options, File validationFolder, - File clangExecutable, List builtinIncludes, File systemResourceDir) { - - var dumper = new ClangAstDumper(false, clangExecutable, builtinIncludes, systemResourceDir, this) - .setBaseFolder(validationFolder) - .setSystemIncludesThreshold(get(SYSTEM_INCLUDES_THRESHOLD)); - return dumper.validateSyntax(source, id, standard, options) ? null : dumper.getLastValidationError(); - } - // private ClangParserData getParserData(Future future) { // try { // return SpecsSystem.get(future); @@ -416,7 +380,7 @@ private Standard getStandard(Collection sources, DataStore options) { private ClangAstData parseSource(File sourceFile, String id, Standard standard, DataStore options, ConcurrentLinkedQueue clangDump, ParallelProgressCounter counter, File parsingFolder, - File clangExecutable, List builtinIncludes, File systemResourceDir) { + ClangFiles clangFiles, ConcurrentLinkedQueue syntaxErrors) { // ConcurrentLinkedQueue clangDump, ConcurrentLinkedQueue workingFolders) { @@ -427,15 +391,25 @@ private ClangAstData parseSource(File sourceFile, String id, Standard standard, // Only show output of console after parsing is done, when using parallel parsing boolean streamConsoleOutput = !get(PARALLEL_PARSING); - ClangAstDumper clangParser = new ClangAstDumper(streamConsoleOutput, clangExecutable, builtinIncludes, - systemResourceDir, this) + ClangAstDumper clangParser = new ClangAstDumper(streamConsoleOutput, clangFiles.clangExecutable(), + clangFiles.builtinIncludes(), clangFiles.systemResourceDir(), this) .setBaseFolder(parsingFolder) .setSystemIncludesThreshold(get(SYSTEM_INCLUDES_THRESHOLD)); // .setUsePlatformLibc(get(ClangAstKeys.USE_PLATFORM_INCLUDES)); counter.print(sourceFile); - // ClavaLog.info("Parsing '" + sourceFile.getAbsolutePath() + "'"); + + // Run the same clang invocation, discard dumper output + if (get(SYNTAX_ONLY)) { + String error = clangParser.validateSyntax(sourceFile, id, standard, options); + if (error != null) { + syntaxErrors.add(error); + } + + return null; + } + ClangAstData clangParserData = clangParser.parse(sourceFile, id, standard, options); if (get(SHOW_CLANG_DUMP)) { diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/dumper/ClangAstDumper.java b/ClangAstParser/src/pt/up/fe/specs/clang/dumper/ClangAstDumper.java index 3f90a5df3..fd2d6f4ef 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/dumper/ClangAstDumper.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/dumper/ClangAstDumper.java @@ -141,8 +141,10 @@ public ClangAstData parse(File sourceFile, String id, Standard standard, DataSto /** * Invokes Clang with the same arguments as parsing, while discarding dumper output. + * + * @return null if the syntax is valid, otherwise an error message */ - public boolean validateSyntax(File sourceFile, String id, Standard standard, DataStore config) { + public String validateSyntax(File sourceFile, String id, Standard standard, DataStore config) { if (config.get(ClangAstKeys.USES_CILK)) { sourceFile = new CilkParser().prepareCilkFile(sourceFile); } @@ -150,16 +152,12 @@ public boolean validateSyntax(File sourceFile, String id, Standard standard, Dat validationOnly = true; try { parsePrivate(sourceFile, id, standard, config); - return lastValidationError == null; + return lastValidationError; } finally { validationOnly = false; } } - public String getLastValidationError() { - return lastValidationError; - } - private ClangAstData parsePrivate(File sourceFile, String id, Standard standard, DataStore config) { ClavaLog.debug(() -> "Data store config for single file parser: " + config); @@ -379,8 +377,6 @@ private void addCudaPathArgument(List arguments, String cudaPath) { private String validateSyntax(List arguments, File sourceFile, String id) { lastWorkingFolder = SpecsIo.mkdir(baseFolder, sourceFile.getName() + "_" + id); - SpecsIo.deleteFolderContents(lastWorkingFolder); - workingFolders.add(lastWorkingFolder); var output = SpecsSystem.runProcess(arguments, lastWorkingFolder, this::discardOutput, diff --git a/ClavaWeaver/src/pt/up/fe/specs/clava/weaver/CxxWeaver.java b/ClavaWeaver/src/pt/up/fe/specs/clava/weaver/CxxWeaver.java index 47fc313f3..210f92029 100644 --- a/ClavaWeaver/src/pt/up/fe/specs/clava/weaver/CxxWeaver.java +++ b/ClavaWeaver/src/pt/up/fe/specs/clava/weaver/CxxWeaver.java @@ -1232,8 +1232,9 @@ public boolean rebuildAst(boolean update) { currentBases = rebuildBases; if (!update) { - newCodeParser().validateSyntax(writtenFiles, - addSourceIncludes(writtenFiles, rebuildOptions, extraOptions), context); + CodeParser codeParser = newCodeParser(); + codeParser.set(ParallelCodeParser.SYNTAX_ONLY, true); + codeParser.parse(writtenFiles, addSourceIncludes(writtenFiles, rebuildOptions, extraOptions), context); currentBases = previousBases; return true; } From 4e3540a88ff054a485a397393ada7c27db018ee3 Mon Sep 17 00:00:00 2001 From: "L. Sousa" Date: Sat, 5 Sep 2026 00:41:52 +0100 Subject: [PATCH 4/4] refactor: drop cosmetic temp folder rename --- .../pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java index 909624dbc..2118f8447 100644 --- a/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java +++ b/ClangAstParser/src/pt/up/fe/specs/clang/codeparser/ParallelCodeParser.java @@ -124,8 +124,7 @@ public App parse(List inputSources, List compilerOptions, ClavaCon ClavaLog.info("Found " + sources.size() + " source files"); // ClavaLog.debug(() -> "[ParallelCodeParser] Files to parse:" + sources); - File parsingFolder = SpecsIo - .getTempFolder((syntaxOnly ? "clava_syntax_validation" : "clava_parsing") + "_" + UUID.randomUUID()); + File parsingFolder = SpecsIo.getTempFolder("clava_parsing_" + UUID.randomUUID().toString()); ClavaLog.debug(() -> "Parsing using folder '" + parsingFolder + "'"); // AtomicInteger currentSourceFileIndex = new AtomicInteger(0);