Skip to content

Commit b95c30e

Browse files
committed
Added code-completion infrastructure
1 parent 6fc6c15 commit b95c30e

File tree

4 files changed

+199
-2
lines changed

4 files changed

+199
-2
lines changed

CodeCompletion.cpp

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* This file is part of arduino-preprocessor.
3+
*
4+
* Copyright 2017 BCMI LABS SA
5+
*
6+
* arduino-preprocessor is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (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
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*
20+
* As a special exception, you may use this file as part of a free software
21+
* library without restriction. Specifically, if other files instantiate
22+
* templates or use macros or inline functions from this file, or you compile
23+
* this file and link it with other files to produce an executable, this
24+
* file does not by itself cause the resulting executable to be covered by
25+
* the GNU General Public License. This exception does not however
26+
* invalidate any other reasons why the executable file might be covered by
27+
* the GNU General Public License.
28+
*/
29+
30+
#include <clang/Basic/TargetInfo.h>
31+
#include <clang/Frontend/CompilerInstance.h>
32+
#include <clang/Frontend/FrontendOptions.h>
33+
#include <clang/Frontend/FrontendActions.h>
34+
#include <clang/Lex/Preprocessor.h>
35+
#include <clang/Lex/PreprocessorOptions.h>
36+
#include <clang/Sema/Sema.h>
37+
#include <clang/Sema/CodeCompleteOptions.h>
38+
#include <clang/Sema/CodeCompleteConsumer.h>
39+
40+
#include <iostream>
41+
42+
#include "CommandLine.hpp"
43+
#include "utils.hpp"
44+
45+
using namespace clang;
46+
using namespace llvm;
47+
using namespace std;
48+
49+
class CustomCodeCompleteConsumer : public CodeCompleteConsumer {
50+
CodeCompletionTUInfo TUInfo;
51+
52+
public:
53+
54+
CustomCodeCompleteConsumer(const CodeCompleteOptions &opts) : CodeCompleteConsumer(opts, false),
55+
TUInfo(std::make_shared<GlobalCodeCompletionAllocator>()) {
56+
}
57+
58+
void ProcessCodeCompleteResults(Sema &s, CodeCompletionContext ctx, CodeCompletionResult *res, unsigned n) override {
59+
60+
}
61+
62+
/*
63+
void ProcessOverloadCandidates(Sema &s, unsigned currArg, OverloadCandidate *candidates, unsigned n) {
64+
}
65+
*/
66+
67+
virtual CodeCompletionAllocator &getAllocator() override {
68+
return TUInfo.getAllocator();
69+
}
70+
71+
virtual CodeCompletionTUInfo &getCodeCompletionTUInfo() override {
72+
return TUInfo;
73+
}
74+
};
75+
76+
int FindRealLineForCodeCompletion(string &code, string &filename, int line) {
77+
int curr = 0;
78+
int real = 0;
79+
bool inFile = false;
80+
for (string &l : split(code, '\n')) {
81+
real++;
82+
curr++;
83+
if (startsWith(l, "# ") || startsWith(l, "#line ")) {
84+
vector<string> fields = split(l, ' ');
85+
int marker;
86+
if (stringToInt(fields[1], &marker)) {
87+
curr = marker;
88+
}
89+
if (fields[2].find(filename) != string::npos) {
90+
inFile = true;
91+
} else {
92+
inFile = false;
93+
}
94+
}
95+
96+
if (inFile && curr == line) {
97+
if (debugOutput) {
98+
cerr << "Code-completions at line " << real << "\n";
99+
}
100+
return real;
101+
}
102+
}
103+
104+
// Not found... fallback to input line
105+
if (debugOutput) {
106+
cerr << "Sorry! source code line not found...\n";
107+
}
108+
return -1;
109+
}
110+
111+
void DoCodeCompletion(const string &filename, const string &code, int line, int col) {
112+
CompilerInstance ci;
113+
ci.createDiagnostics();
114+
115+
// Hide diagnostics
116+
ci.getDiagnostics().setClient(new IgnoringDiagConsumer());
117+
118+
shared_ptr<clang::TargetOptions> tOpts = make_shared<clang::TargetOptions>();
119+
tOpts->Triple = sys::getDefaultTargetTriple();
120+
ci.setTarget(TargetInfo::CreateTargetInfo(ci.getDiagnostics(), tOpts));
121+
122+
LangOptions &lOpts = ci.getLangOpts();
123+
lOpts.CPlusPlus = true;
124+
lOpts.CPlusPlus11 = true;
125+
lOpts.Bool = true;
126+
lOpts.GNUMode = true;
127+
128+
CodeCompleteOptions ccOpts;
129+
ccOpts.IncludeMacros = 1;
130+
ccOpts.IncludeCodePatterns = 1;
131+
ccOpts.IncludeGlobals = 1;
132+
ccOpts.IncludeBriefComments = 1;
133+
ci.setCodeCompletionConsumer(new CustomCodeCompleteConsumer(ccOpts));
134+
135+
FrontendOptions& fOpts = ci.getFrontendOpts();
136+
fOpts.Inputs.push_back(FrontendInputFile(filename, InputKind::IK_CXX));
137+
fOpts.CodeCompletionAt.FileName = filename;
138+
fOpts.CodeCompletionAt.Line = line;
139+
fOpts.CodeCompletionAt.Column = col;
140+
141+
unique_ptr<MemoryBuffer> buff(MemoryBuffer::getMemBuffer(code, filename));
142+
143+
PreprocessorOptions& pOpts = ci.getPreprocessorOpts();
144+
pOpts.clearRemappedFiles();
145+
pOpts.addRemappedFile(filename, buff.release());
146+
147+
SyntaxOnlyAction action;
148+
if (action.BeginSourceFile(ci, ci.getFrontendOpts().Inputs[0])) {
149+
action.Execute();
150+
action.EndSourceFile();
151+
}
152+
}

CodeCompletion.hpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* This file is part of arduino-preprocessor.
3+
*
4+
* Copyright 2017 BCMI LABS SA
5+
*
6+
* arduino-preprocessor is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (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
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*
20+
* As a special exception, you may use this file as part of a free software
21+
* library without restriction. Specifically, if other files instantiate
22+
* templates or use macros or inline functions from this file, or you compile
23+
* this file and link it with other files to produce an executable, this
24+
* file does not by itself cause the resulting executable to be covered by
25+
* the GNU General Public License. This exception does not however
26+
* invalidate any other reasons why the executable file might be covered by
27+
* the GNU General Public License.
28+
*/
29+
30+
#pragma once
31+
32+
using namespace std;
33+
34+
int FindRealLineForCodeCompletion(string &code, string &filename, int line);
35+
36+
void DoCodeCompletion(const string &sourceFilename, const string &code, int line, int col);

main.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@
4646
#include <list>
4747

4848
#include "ArduinoDiagnosticConsumer.hpp"
49-
#include "Config.hpp"
5049
#include "CommandLine.hpp"
50+
#include "Config.hpp"
51+
#include "CodeCompletion.hpp"
5152
#include "IdentifiersList.hpp"
53+
#include "utils.hpp"
5254

5355
using namespace clang;
5456
using namespace clang::ast_matchers;
@@ -272,5 +274,12 @@ int main(int argc, const char **argv) {
272274
cout << preprocessedSketch;
273275
}
274276

277+
if (outputCodeCompletions) {
278+
int line = FindRealLineForCodeCompletion(preprocessedSketch, codeCompleteFilename, codeCompleteLine);
279+
if (line != -1) {
280+
DoCodeCompletion(optParser.getSourcePathList()[0], preprocessedSketch, line, codeCompleteCol);
281+
}
282+
}
283+
275284
return res;
276285
}

package-arduino-preprocessor.bash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ CXXFLAGS=`clang/bin/llvm-config --cxxflags`
108108
LDFLAGS=`clang/bin/llvm-config --ldflags`
109109
LLVMLIBS=`clang/bin/llvm-config --libs --system-libs`
110110
CLANGLIBS=`ls clang/lib/libclang*.a | sed s/.*libclang/-lclang/ | sed s/.a$//`
111-
SOURCES="main.cpp ArduinoDiagnosticConsumer.cpp CommandLine.cpp IdentifiersList.cpp"
111+
SOURCES="main.cpp ArduinoDiagnosticConsumer.cpp CommandLine.cpp IdentifiersList.cpp CodeCompletion.cpp"
112112
$CXX $SOURCES -o objdir/arduino-preprocessor $CXXFLAGS $LDFLAGS -Wl,--start-group $LLVMLIBS $CLANGLIBS -Wl,--end-group
113113

114114
rm -f arduino-preprocessor-${OUTPUT_VERSION}-${OUTPUT_TAG}.tar.bz2

0 commit comments

Comments
 (0)