Skip to content

Commit d0b3f89

Browse files
committed
Static code analysis options
1 parent 0a262ed commit d0b3f89

File tree

17 files changed

+625
-77
lines changed

17 files changed

+625
-77
lines changed
Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,80 @@
11
package com.duy.ccppcompiler.compiler;
22

33
import android.os.Bundle;
4-
import android.preference.PreferenceFragment;
54
import android.support.annotation.Nullable;
5+
import android.support.design.widget.TabLayout;
6+
import android.support.v4.app.Fragment;
7+
import android.support.v4.app.FragmentPagerAdapter;
8+
import android.support.v4.view.ViewPager;
9+
import android.support.v7.preference.PreferenceFragmentCompat;
610
import android.support.v7.widget.Toolbar;
711

812
import com.duy.ccppcompiler.R;
913
import com.jecelyin.editor.v2.ThemeSupportActivity;
1014

11-
import static com.duy.common.preferences.PreferencesNative.bindPreferenceSummaryToValue;
15+
import static com.duy.common.preferences.PreferencesSupportV7.bindPreferenceSummaryToValue;
1216

1317
public class CompilerSettingActivity extends ThemeSupportActivity {
1418
@Override
1519
protected void onCreate(@Nullable Bundle savedInstanceState) {
1620
super.onCreate(savedInstanceState);
17-
setContentView(R.layout.activity_term_setting);
21+
setContentView(R.layout.activity_compiler_setting);
1822
Toolbar toolbar = findViewById(com.duy.ide.editor.editor.R.id.toolbar);
1923
setSupportActionBar(toolbar);
2024
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
2125
setTitle(com.duy.ide.editor.editor.R.string.settings);
2226

23-
// Display the fragment as the main content.
24-
getFragmentManager()
25-
.beginTransaction()
26-
.replace(com.duy.ide.editor.editor.R.id.content, new SettingsFragment())
27-
.commit();
27+
ViewPager viewPager = findViewById(R.id.view_pager);
28+
viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
29+
@Override
30+
public Fragment getItem(int position) {
31+
switch (position) {
32+
case 0:
33+
return new CompilerOptionsFragment();
34+
case 1:
35+
return new StaticCodeAnalysisSetting();
36+
default:
37+
return null;
38+
}
39+
}
40+
41+
@Override
42+
public int getCount() {
43+
return 2;
44+
}
45+
46+
@Nullable
47+
@Override
48+
public CharSequence getPageTitle(int position) {
49+
switch (position) {
50+
case 0:
51+
return getString(R.string.compiler);
52+
case 1:
53+
return getString(R.string.code_analysis);
54+
default:
55+
return null;
56+
}
57+
}
58+
});
59+
60+
TabLayout tabLayout = findViewById(R.id.tab_layout);
61+
tabLayout.setupWithViewPager(viewPager);
2862
}
2963

30-
public static class SettingsFragment extends PreferenceFragment {
64+
public static class CompilerOptionsFragment extends PreferenceFragmentCompat {
3165
@Override
32-
public void onCreate(@Nullable Bundle savedInstanceState) {
33-
super.onCreate(savedInstanceState);
66+
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
3467
addPreferencesFromResource(R.xml.preferences_compiler);
3568
bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_option_optimization_level)));
3669
bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_option_language_standard)));
3770
}
3871
}
72+
73+
public static class StaticCodeAnalysisSetting extends PreferenceFragmentCompat {
74+
75+
@Override
76+
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
77+
addPreferencesFromResource(R.xml.preferences_cppcheck);
78+
}
79+
}
3980
}

app/src/main/java/com/duy/ccppcompiler/compiler/analyze/CppCheckAnalyzer.java

Lines changed: 98 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@
1717

1818
package com.duy.ccppcompiler.compiler.analyze;
1919

20+
import android.annotation.SuppressLint;
2021
import android.content.Context;
22+
import android.core.widget.EditAreaView;
23+
import android.os.AsyncTask;
2124
import android.os.Handler;
2225
import android.support.annotation.NonNull;
2326
import android.text.Editable;
2427
import android.text.TextWatcher;
2528

2629
import com.duy.ccppcompiler.compiler.shell.CommandBuilder;
2730
import com.duy.ccppcompiler.compiler.shell.CommandResult;
28-
import com.duy.ccppcompiler.compiler.shell.OutputParser;
2931
import com.duy.ccppcompiler.compiler.shell.Shell;
3032
import com.duy.common.DLog;
3133
import com.duy.ide.diagnostic.Diagnostic;
@@ -37,23 +39,45 @@
3739
import java.io.File;
3840
import java.io.IOException;
3941
import java.util.ArrayList;
40-
import java.util.regex.Pattern;
4142

4243
/**
4344
* https://sourceforge.net/p/cppcheck/wiki/Home/
45+
* <p>
46+
* # enable warning messages
47+
* cppcheck --enable=warning file.c
48+
* <p>
49+
* # enable performance messages
50+
* cppcheck --enable=performance file.c
51+
* <p>
52+
* # enable information messages
53+
* cppcheck --enable=information file.c
54+
* <p>
55+
* # For historical reasons, --enable=style enables warning, performance,
56+
* # portability and style messages. These are all reported as "style" when
57+
* # using the old xml format.
58+
* cppcheck --enable=style file.c
59+
* <p>
60+
* # enable warning and performance messages
61+
* cppcheck --enable=warning,performance file.c
62+
* <p>
63+
* # enable unusedFunction checking. This is not enabled by --enable=style
64+
* # because it doesn't work well on libraries.
65+
* cppcheck --enable=unusedFunction file.c
66+
* <p>
67+
* # enable all messages
68+
* cppcheck --enable=all
4469
*/
4570
public class CppCheckAnalyzer implements ICodeAnalyser {
4671
public static final long DELAY_TIME = 300;
4772
private static final String TAG = "CppCheckAnalyzer";
4873

4974
private static final String CPPCHECK_PROGRAM = "cppcheck";
50-
private static final String TEMPLATE = "--template=\"{file}:{line}:{message}\"";
51-
private static final Pattern TEMPLATE_PATTERN = Pattern.compile("^(\\S+):([0-9]+):(.*)");
5275

5376
private final Context mContext;
5477
private final IEditorDelegate mEditorDelegate;
5578
private final android.os.Handler mHandler = new Handler();
5679
private DiagnosticPresenter mDiagnosticPresenter;
80+
private AnalyzeTask mAnalyzeTask;
5781
private final Runnable mAnalyze = new Runnable() {
5882
@Override
5983
public void run() {
@@ -72,37 +96,14 @@ public CppCheckAnalyzer(@NonNull Context context, @NonNull IEditorDelegate deleg
7296
}
7397

7498
private void analyzeImpl() throws IOException {
75-
File originFile = mEditorDelegate.getDocument().getFile();
76-
File tmpFile = new File(getCppCheckTmpDir(), originFile.getName());
77-
78-
LocalFileWriter localFileWriter = new LocalFileWriter(tmpFile, "UTF-8");
79-
localFileWriter.writeToFile(mEditorDelegate.getEditText().getText());
80-
81-
CommandBuilder builder = new CommandBuilder(CPPCHECK_PROGRAM);
82-
builder.addFlags(TEMPLATE);
83-
builder.addFlags(tmpFile.getAbsolutePath());
84-
85-
String cmd = builder.build();
86-
CommandResult result = Shell.exec(mContext, tmpFile.getParent(), cmd);
87-
if (DLog.DEBUG) DLog.d(TAG, "result = " + result);
88-
String message = result.getMessage().replace(tmpFile.getAbsolutePath(), originFile.getAbsolutePath());
89-
90-
DiagnosticsCollector diagnosticsCollector = new DiagnosticsCollector();
91-
OutputParser parser = new OutputParser(diagnosticsCollector);
92-
parser.parse(message);
93-
94-
ArrayList<Diagnostic> diagnostics = diagnosticsCollector.getDiagnostics();
95-
mDiagnosticPresenter.setDiagnostics(diagnostics);
96-
}
97-
98-
private File getCppCheckTmpDir() {
99-
File dir = new File(mContext.getCacheDir(), "cppcheck/tmp");
100-
if (!dir.exists()) {
101-
dir.mkdirs();
99+
if (mAnalyzeTask != null) {
100+
mAnalyzeTask.cancel(true);
102101
}
103-
return dir;
102+
mAnalyzeTask = new AnalyzeTask(mContext, mEditorDelegate, mDiagnosticPresenter);
103+
mAnalyzeTask.execute();
104104
}
105105

106+
106107
@Override
107108
public void start() {
108109
mEditorDelegate.getEditText().addTextChangedListener(new TextWatcher() {
@@ -124,4 +125,69 @@ public void afterTextChanged(Editable s) {
124125
}
125126
});
126127
}
128+
129+
@SuppressLint("StaticFieldLeak")
130+
private static class AnalyzeTask extends AsyncTask<Void, Void, ArrayList<Diagnostic>> {
131+
132+
private final Context mContext;
133+
private final DiagnosticPresenter mDiagnosticPresenter;
134+
private IEditorDelegate mEditorDelegate;
135+
136+
public AnalyzeTask(Context mContext, IEditorDelegate delegate, DiagnosticPresenter mDiagnosticPresenter) {
137+
this.mContext = mContext;
138+
this.mEditorDelegate = delegate;
139+
this.mDiagnosticPresenter = mDiagnosticPresenter;
140+
}
141+
142+
@Override
143+
protected ArrayList<Diagnostic> doInBackground(Void... voids) {
144+
EditAreaView editText = mEditorDelegate.getEditText();
145+
146+
File originFile = mEditorDelegate.getDocument().getFile();
147+
File tmpFile = new File(getCppCheckTmpDir(), originFile.getName());
148+
149+
LocalFileWriter localFileWriter = new LocalFileWriter(tmpFile, "UTF-8");
150+
try {
151+
localFileWriter.writeToFile(editText.getText());
152+
} catch (IOException e) {
153+
e.printStackTrace();
154+
return null;
155+
}
156+
157+
CommandBuilder builder = new CommandBuilder(CPPCHECK_PROGRAM);
158+
builder.addFlags(CppCheckOutputParser.TEMPLATE);
159+
builder.addFlags(tmpFile.getAbsolutePath());
160+
builder.addFlags("--enable=warning,performance,information");
161+
162+
String cmd = builder.build();
163+
CommandResult result = Shell.exec(mContext, tmpFile.getParent(), cmd);
164+
if (isCancelled()) {
165+
return null;
166+
}
167+
168+
if (DLog.DEBUG) DLog.d(TAG, "result = " + result);
169+
String message = result.getMessage().replace(tmpFile.getAbsolutePath(), originFile.getAbsolutePath());
170+
DiagnosticsCollector diagnosticsCollector = new DiagnosticsCollector();
171+
CppCheckOutputParser parser = new CppCheckOutputParser(diagnosticsCollector);
172+
parser.parse(message);
173+
174+
return diagnosticsCollector.getDiagnostics();
175+
}
176+
177+
private File getCppCheckTmpDir() {
178+
File dir = new File(mContext.getCacheDir(), "cppcheck/tmp");
179+
if (!dir.exists()) {
180+
dir.mkdirs();
181+
}
182+
return dir;
183+
}
184+
185+
@Override
186+
protected void onPostExecute(ArrayList<Diagnostic> diagnostics) {
187+
super.onPostExecute(diagnostics);
188+
if (diagnostics != null && !isCancelled()) {
189+
mDiagnosticPresenter.setDiagnostics(diagnostics);
190+
}
191+
}
192+
}
127193
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (C) 2018 Duy Tran Le
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.duy.ccppcompiler.compiler.analyze;
19+
20+
import com.duy.ide.diagnostic.Diagnostic;
21+
import com.duy.ide.diagnostic.DiagnosticFactory;
22+
import com.duy.ide.diagnostic.DiagnosticsCollector;
23+
import com.duy.ide.diagnostic.model.Kind;
24+
25+
import java.io.LineNumberReader;
26+
import java.io.StringReader;
27+
import java.util.regex.Matcher;
28+
import java.util.regex.Pattern;
29+
30+
/**
31+
* https://gcc.gnu.org/onlinedocs/gcc-3.3.5/gnat_ug_unx/Output-and-Error-Message-Control.html
32+
* <p>
33+
* https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Diagnostic-Message-Formatting-Options.html
34+
* <p>
35+
*
36+
*
37+
* Created by Duy on 28-Apr-18.
38+
*/
39+
40+
public class CppCheckOutputParser {
41+
42+
private static final Pattern TEMPLATE_PATTERN = Pattern.compile("^(\\S+):([0-9]+):([^:]+):(.*)");
43+
public static final String TEMPLATE = "--template=\"{file}:{line}:{severity}:{message}\"";
44+
45+
private DiagnosticsCollector diagnosticsCollector;
46+
47+
public CppCheckOutputParser(DiagnosticsCollector diagnosticsCollector) {
48+
this.diagnosticsCollector = diagnosticsCollector;
49+
}
50+
51+
public void parse(String inputData) {
52+
try {
53+
StringReader stringReader = new StringReader(inputData);
54+
LineNumberReader lineReader = new LineNumberReader(stringReader);
55+
String line;
56+
while ((line = lineReader.readLine()) != null) {
57+
Matcher matcher = TEMPLATE_PATTERN.matcher(line);
58+
if (matcher.find()) {
59+
String filePath = matcher.group(1);
60+
int lineNumber = Integer.parseInt(matcher.group(2));
61+
Kind type = DiagnosticFactory.createType(matcher.group(3));
62+
String message = matcher.group(4);
63+
Diagnostic diagnostic = DiagnosticFactory.create(type, filePath, lineNumber, Diagnostic.NOPOS, message);
64+
diagnosticsCollector.report(diagnostic);
65+
}
66+
}
67+
} catch (Exception e) {
68+
//should not happened
69+
e.printStackTrace();
70+
}
71+
}
72+
}

0 commit comments

Comments
 (0)