This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 255657
Collapse All | Expand All

(-)a/cnd.highlight/src/org/netbeans/modules/cnd/highlight/hints/formatstring/FormatStringAudit.java (-121 / +177 lines)
Lines 56-63 Link Here
56
import org.netbeans.cnd.api.lexer.CppTokenId;
56
import org.netbeans.cnd.api.lexer.CppTokenId;
57
import org.netbeans.editor.BaseDocument;
57
import org.netbeans.editor.BaseDocument;
58
import org.netbeans.modules.cnd.analysis.api.AnalyzerResponse;
58
import org.netbeans.modules.cnd.analysis.api.AnalyzerResponse;
59
import org.netbeans.modules.cnd.api.model.CsmClass;
59
import org.netbeans.modules.cnd.api.model.CsmFile;
60
import org.netbeans.modules.cnd.api.model.CsmFile;
61
import org.netbeans.modules.cnd.api.model.CsmFunction;
62
import org.netbeans.modules.cnd.api.model.CsmFunctionDefinition;
63
import org.netbeans.modules.cnd.api.model.CsmNamespaceDefinition;
60
import org.netbeans.modules.cnd.api.model.CsmObject;
64
import org.netbeans.modules.cnd.api.model.CsmObject;
65
import org.netbeans.modules.cnd.api.model.CsmOffsetableDeclaration;
66
import org.netbeans.modules.cnd.api.model.deep.CsmCompoundStatement;
67
import org.netbeans.modules.cnd.api.model.deep.CsmStatement;
61
import org.netbeans.modules.cnd.api.model.syntaxerr.AbstractCodeAudit;
68
import org.netbeans.modules.cnd.api.model.syntaxerr.AbstractCodeAudit;
62
import static org.netbeans.modules.cnd.api.model.syntaxerr.AbstractCodeAudit.toSeverity;
69
import static org.netbeans.modules.cnd.api.model.syntaxerr.AbstractCodeAudit.toSeverity;
63
import org.netbeans.modules.cnd.api.model.syntaxerr.AuditPreferences;
70
import org.netbeans.modules.cnd.api.model.syntaxerr.AuditPreferences;
Lines 87-92 Link Here
87
public class FormatStringAudit extends AbstractCodeAudit {
94
public class FormatStringAudit extends AbstractCodeAudit {
88
    
95
    
89
    private static final boolean CHECKS_ENABLED;
96
    private static final boolean CHECKS_ENABLED;
97
    private List<FormattedPrintFunction> result;
90
    
98
    
91
    static {
99
    static {
92
        String checksEnabled = System.getProperty("printf.check.enable"); //NOI18N
100
        String checksEnabled = System.getProperty("printf.check.enable"); //NOI18N
Lines 113-246 Link Here
113
            if (request.isCancelled()) {
121
            if (request.isCancelled()) {
114
                return;
122
                return;
115
            }
123
            }
116
            
117
            Document doc_ = request.getDocument();
124
            Document doc_ = request.getDocument();
118
            if (doc_ == null) {
125
            if (doc_ == null) {
119
                CloneableEditorSupport ces = CsmUtilities.findCloneableEditorSupport(file);
126
                CloneableEditorSupport ces = CsmUtilities.findCloneableEditorSupport(file);
120
                doc_ = CsmUtilities.openDocument(ces);
127
                doc_ = CsmUtilities.openDocument(ces);
121
            }
128
            }
122
            final Document doc = doc_;
129
            final Document doc = doc_;
123
            final List<FormattedPrintFunction> result = new LinkedList<>();
124
            
130
            
125
            Collection<CsmReference> references = CsmReferenceResolver.getDefault().getReferences(file);
131
            result = new LinkedList<>();
126
            for (CsmReference reference : references) {
132
            visit(file.getDeclarations(), file, doc, request, response);
127
                CsmObject object = reference.getReferencedObject();
128
                if (Utilities.isFormattedPrintFunction(object)) {
129
                    final int startOffset = reference.getStartOffset();
130
                    
131
                    doc.render(new Runnable() {
132
                        @Override
133
                        public void run() {
134
                            TokenSequence<TokenId> docTokenSequence = CndLexerUtilities.getCppTokenSequence(doc, startOffset, false, true);
135
                            if (docTokenSequence == null) {
136
                                return;
137
                            }
138
                            
139
                            final CsmReferenceResolver rr = CsmReferenceResolver.getDefault();
140
                            StringBuilder paramBuf = new StringBuilder();
141
                            ArrayList<Parameter> params = new ArrayList<>();
142
                            
143
                            State state = State.DEFAULT;
144
                            boolean formatFlag = false;  // detect was format string already processed
145
                            StringBuilder formatString = null;
146
                            int paramOffset = -1;
147
                            int bracketsCounter = 0;
148
                            int formatStringOffset = -1;
149
                            boolean doNotResolveType = false;
150
                            
151
                            while (docTokenSequence.moveNext()) {
152
                                Token<TokenId> token = docTokenSequence.token();
153
                                TokenId tokenId = token.id();
154
                                if (tokenId.equals(CppTokenId.IDENTIFIER) && state == State.DEFAULT) {
155
                                    CsmReference reference = rr.findReference(file, doc, docTokenSequence.offset());
156
                                    CsmObject object = reference.getReferencedObject();
157
                                    state = State.START;
158
                                } else if (tokenId.equals(CppTokenId.LPAREN) && state == State.START) {
159
                                    state = State.IN_PARAM;
160
                                } else if (tokenId.equals(CppTokenId.LPAREN) && state == State.IN_PARAM) {
161
                                    state = State.IN_PARAM_BRACKET;
162
                                    bracketsCounter++;
163
                                    if (formatFlag) {
164
                                        paramBuf.append(token.text());
165
                                        if (paramOffset == -1) {
166
                                            paramOffset = docTokenSequence.offset();
167
                                        }
168
                                    }
169
                                } else if (tokenId.equals(CppTokenId.LPAREN) && state == State.IN_PARAM_BRACKET) {
170
                                    bracketsCounter++;
171
                                    if (formatFlag) {
172
                                        paramBuf.append(token.text());
173
                                        if (paramOffset == -1) {
174
                                            paramOffset = docTokenSequence.offset();
175
                                        }
176
                                    }
177
                                } else if (tokenId.equals(CppTokenId.RPAREN) && state == State.IN_PARAM_BRACKET) {
178
                                    bracketsCounter--;
179
                                    if (bracketsCounter == 0) {
180
                                        state = State.IN_PARAM;
181
                                    }
182
                                    if (formatFlag) {
183
                                        paramBuf.append(token.text());
184
                                        if (paramOffset == -1) {
185
                                            paramOffset = docTokenSequence.offset();
186
                                        }
187
                                    }
188
                                } else if (tokenId.equals(CppTokenId.RPAREN) && state == State.IN_PARAM) {
189
                                    if (paramBuf.length() > 0) {
190
                                        params.add(new Parameter(paramBuf.toString(), paramOffset, !doNotResolveType));
191
                                        paramOffset = -1;
192
                                    }
193
                                    result.add(new FormattedPrintFunction(file
194
                                                                         ,formatStringOffset
195
                                                                         ,(formatString == null) ? "" : formatString.toString()
196
                                                                         ,params));
197
                                    return;
198
                                } else if (state == State.IN_PARAM && tokenId.equals(CppTokenId.STRING_LITERAL) && !formatFlag) {
199
                                    params = new ArrayList<>();
200
                                    if (formatString == null) {
201
                                        formatString = new StringBuilder();
202
                                    }
203
                                    formatString.append(token.text().toString());
204
                                    formatStringOffset = docTokenSequence.offset();
205
                                } else if (state == State.IN_PARAM && !formatFlag && formatString != null && tokenId.equals(CppTokenId.COMMA)) {
206
                                    formatFlag = true;
207
                                } else if (state == State.IN_PARAM && formatFlag && tokenId.equals(CppTokenId.COMMA)) {
208
                                    if (paramBuf.length() > 0) {
209
                                        params.add(new Parameter(paramBuf.toString(), paramOffset, !doNotResolveType));
210
                                        paramOffset = -1;
211
                                    }
212
                                    doNotResolveType = false;
213
                                    paramBuf = new StringBuilder();
214
                                } else if ((state == State.IN_PARAM || state == State.IN_PARAM_BRACKET) 
215
                                        && !tokenId.primaryCategory().equals(CppTokenId.COMMENT_CATEGORY)
216
                                        && formatFlag) {
217
                                    if (paramBuf.length() == 0 && tokenId.primaryCategory().equals(CppTokenId.WHITESPACE_CATEGORY)) {
218
                                        // skip whitespoaces before the parameter
219
                                        continue;
220
                                    }
221
                                    if (paramOffset == -1) {
222
                                        // save start offset of the parameter
223
                                        paramOffset = docTokenSequence.offset();
224
                                    }
225
                                    // skip macro parameters
226
                                    CsmReference ref = rr.findReference(file, doc, docTokenSequence.offset());
227
                                    if (ref != null && CsmKindUtilities.isMacro(ref.getReferencedObject())) {
228
                                        doNotResolveType = true;
229
                                    }
230
                                    paramBuf.append(token.text());
231
                                } else if ((state == State.IN_PARAM || state == State.IN_PARAM_BRACKET) 
232
                                        && !tokenId.primaryCategory().equals(CppTokenId.COMMENT_CATEGORY)) {
233
                                    // skip check in case of string concatenation with macros
234
                                    CsmReference ref = rr.findReference(file, doc, docTokenSequence.offset());
235
                                    if (ref != null && CsmKindUtilities.isMacro(ref.getReferencedObject())) {
236
                                        break;
237
                                    }
238
                                }
239
                            }
240
                        }
241
                    });
242
                }
243
            }
244
            
133
            
245
            List<FormatError> errors = new LinkedList<>();
134
            List<FormatError> errors = new LinkedList<>();
246
            for (FormattedPrintFunction function : result) {
135
            for (FormattedPrintFunction function : result) {
Lines 271-276 Link Here
271
        }
160
        }
272
    }
161
    }
273
    
162
    
163
    private void visit(Collection<? extends CsmOffsetableDeclaration> decls, final CsmFile file, final Document doc, CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
164
        for (CsmOffsetableDeclaration decl : decls) {
165
            if (CsmKindUtilities.isClass(decl)) {
166
                visit(((CsmClass) decl).getMembers(), file, doc, request, response);
167
            } else if (CsmKindUtilities.isNamespaceDefinition(decl)) {
168
                visit(((CsmNamespaceDefinition) decl).getDeclarations(), file, doc, request, response);
169
            } else if (CsmKindUtilities.isFunctionDeclaration(decl)) {
170
                visit(((CsmFunction) decl).getDefinition(), file, doc, request, response);
171
            } else if (CsmKindUtilities.isFunctionDefinition(decl)) {
172
                visit((CsmFunctionDefinition) decl, file, doc, request, response);
173
            }
174
        }
175
    }
176
    
177
    private void visit(CsmFunctionDefinition function, final CsmFile file, final Document doc, CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
178
        if (function == null) {
179
            return;
180
        }
181
        if (!file.equals(function.getContainingFile())) {
182
            return;
183
        }
184
        
185
        for (CsmStatement statement : function.getBody().getStatements()) {
186
            if (request.isCancelled()) {
187
                return;
188
            }
189
            
190
            if (CsmKindUtilities.isCompoundStatement(statement)) {
191
                visit((CsmCompoundStatement) statement, file, doc, request, response);
192
            } else {
193
                visit(statement, file, doc, request, response);
194
            }
195
        }
196
    }
197
    
198
    private void visit(CsmCompoundStatement compoundStatement, final CsmFile file, final Document doc, CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
199
        for (CsmStatement statement : compoundStatement.getStatements()) {
200
            if (request.isCancelled()) {
201
                return;
202
            }
203
            
204
            visit(statement, file, doc, request, response);
205
        }
206
    }
207
    
208
    private void visit(CsmStatement statement, final CsmFile file, final Document doc, CsmErrorProvider.Request request, CsmErrorProvider.Response response) {
209
        CsmReference reference = CsmReferenceResolver.getDefault().findReference(file, doc, statement.getStartOffset());
210
        if (reference != null) {
211
            CsmObject object = reference.getReferencedObject();
212
            if (Utilities.isFormattedPrintFunction(object)) {
213
                final int startOffset = reference.getStartOffset();
214
215
                doc.render(new Runnable() {
216
                    @Override
217
                    public void run() {
218
                        TokenSequence<TokenId> docTokenSequence = CndLexerUtilities.getCppTokenSequence(doc, startOffset, false, true);
219
                        if (docTokenSequence == null) {
220
                            return;
221
                        }
222
223
                        final CsmReferenceResolver rr = CsmReferenceResolver.getDefault();
224
                        StringBuilder paramBuf = new StringBuilder();
225
                        ArrayList<Parameter> params = new ArrayList<>();
226
227
                        State state = State.DEFAULT;
228
                        boolean formatFlag = false;  // detect was format string already processed
229
                        StringBuilder formatString = null;
230
                        int paramOffset = -1;
231
                        int bracketsCounter = 0;
232
                        int formatStringOffset = -1;
233
                        boolean doNotResolveType = false;
234
235
                        while (docTokenSequence.moveNext()) {
236
                            Token<TokenId> token = docTokenSequence.token();
237
                            TokenId tokenId = token.id();
238
                            if (tokenId.equals(CppTokenId.IDENTIFIER) && state == State.DEFAULT) {
239
                                CsmReference reference = rr.findReference(file, doc, docTokenSequence.offset());
240
                                CsmObject object = reference.getReferencedObject();
241
                                state = State.START;
242
                            } else if (tokenId.equals(CppTokenId.LPAREN) && state == State.START) {
243
                                state = State.IN_PARAM;
244
                            } else if (tokenId.equals(CppTokenId.LPAREN) && state == State.IN_PARAM) {
245
                                state = State.IN_PARAM_BRACKET;
246
                                bracketsCounter++;
247
                                if (formatFlag) {
248
                                    paramBuf.append(token.text());
249
                                    if (paramOffset == -1) {
250
                                        paramOffset = docTokenSequence.offset();
251
                                    }
252
                                }
253
                            } else if (tokenId.equals(CppTokenId.LPAREN) && state == State.IN_PARAM_BRACKET) {
254
                                bracketsCounter++;
255
                                if (formatFlag) {
256
                                    paramBuf.append(token.text());
257
                                    if (paramOffset == -1) {
258
                                        paramOffset = docTokenSequence.offset();
259
                                    }
260
                                }
261
                            } else if (tokenId.equals(CppTokenId.RPAREN) && state == State.IN_PARAM_BRACKET) {
262
                                bracketsCounter--;
263
                                if (bracketsCounter == 0) {
264
                                    state = State.IN_PARAM;
265
                                }
266
                                if (formatFlag) {
267
                                    paramBuf.append(token.text());
268
                                    if (paramOffset == -1) {
269
                                        paramOffset = docTokenSequence.offset();
270
                                    }
271
                                }
272
                            } else if (tokenId.equals(CppTokenId.RPAREN) && state == State.IN_PARAM) {
273
                                if (paramBuf.length() > 0) {
274
                                    params.add(new Parameter(paramBuf.toString(), paramOffset, !doNotResolveType));
275
                                    paramOffset = -1;
276
                                }
277
                                result.add(new FormattedPrintFunction(file
278
                                                                     ,formatStringOffset
279
                                                                     ,(formatString == null) ? "" : formatString.toString()
280
                                                                     ,params));
281
                                return;
282
                            } else if (state == State.IN_PARAM && tokenId.equals(CppTokenId.STRING_LITERAL) && !formatFlag) {
283
                                params = new ArrayList<>();
284
                                if (formatString == null) {
285
                                    formatString = new StringBuilder();
286
                                }
287
                                formatString.append(token.text().toString());
288
                                formatStringOffset = docTokenSequence.offset();
289
                            } else if (state == State.IN_PARAM && !formatFlag && formatString != null && tokenId.equals(CppTokenId.COMMA)) {
290
                                formatFlag = true;
291
                            } else if (state == State.IN_PARAM && formatFlag && tokenId.equals(CppTokenId.COMMA)) {
292
                                if (paramBuf.length() > 0) {
293
                                    params.add(new Parameter(paramBuf.toString(), paramOffset, !doNotResolveType));
294
                                    paramOffset = -1;
295
                                }
296
                                doNotResolveType = false;
297
                                paramBuf = new StringBuilder();
298
                            } else if ((state == State.IN_PARAM || state == State.IN_PARAM_BRACKET) 
299
                                    && !tokenId.primaryCategory().equals(CppTokenId.COMMENT_CATEGORY)
300
                                    && formatFlag) {
301
                                if (paramBuf.length() == 0 && tokenId.primaryCategory().equals(CppTokenId.WHITESPACE_CATEGORY)) {
302
                                    // skip whitespoaces before the parameter
303
                                    continue;
304
                                }
305
                                if (paramOffset == -1) {
306
                                    // save start offset of the parameter
307
                                    paramOffset = docTokenSequence.offset();
308
                                }
309
                                // skip macro parameters
310
                                CsmReference ref = rr.findReference(file, doc, docTokenSequence.offset());
311
                                if (ref != null && CsmKindUtilities.isMacro(ref.getReferencedObject())) {
312
                                    doNotResolveType = true;
313
                                }
314
                                paramBuf.append(token.text());
315
                            } else if ((state == State.IN_PARAM || state == State.IN_PARAM_BRACKET) 
316
                                    && !tokenId.primaryCategory().equals(CppTokenId.COMMENT_CATEGORY)) {
317
                                // skip check in case of string concatenation with macros
318
                                CsmReference ref = rr.findReference(file, doc, docTokenSequence.offset());
319
                                if (ref != null && CsmKindUtilities.isMacro(ref.getReferencedObject())) {
320
                                    break;
321
                                }
322
                            }
323
                        }
324
                    }
325
                });
326
            }
327
        }
328
    }
329
    
274
    private static enum State {
330
    private static enum State {
275
        DEFAULT,
331
        DEFAULT,
276
        START,
332
        START,

Return to bug 255657