commit
b8982270f2
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
[alias]
|
||||||
|
endtoend_test_objc = //infer/tests/endtoend:objc_endtoend_tests
|
||||||
|
frontend_test_objc = //infer/tests/frontend:objc_frontend_tests
|
||||||
|
|
||||||
|
endtoend_test_java = //infer/tests/endtoend:java_endtoend_tests
|
||||||
|
endtoend_test_c = //infer/tests/endtoend:edgc_endtoend_tests
|
||||||
|
|
||||||
|
integration_tests = //infer/tests:integration_tests
|
||||||
|
objc = //infer/tests:objc_tests
|
||||||
|
c = //infer/tests:c_tests
|
||||||
|
cpp = //infer/tests:cpp_tests
|
||||||
|
objcpp = //infer/tests:objcpp_tests
|
||||||
|
clang = //infer/tests:clang_tests
|
||||||
|
java = //infer/tests/endtoend:java_endtoend_tests
|
||||||
|
|
||||||
|
java_libraries = //dependencies/java:java_libraries
|
||||||
|
|
||||||
|
infer = //infer/tests/endtoend/java/infer:infer
|
||||||
|
eradicate = //infer/tests/endtoend/java/eradicate:eradicate
|
||||||
|
checkers = //infer/tests/endtoend/java/checkers:checkers
|
||||||
|
tracing = //infer/tests/endtoend/java/tracing:tracing
|
||||||
|
|
||||||
|
[project]
|
||||||
|
ignore = .git, .ml, .mli
|
@ -0,0 +1,89 @@
|
|||||||
|
# Generated files #
|
||||||
|
###################
|
||||||
|
*.pyc
|
||||||
|
*.specs
|
||||||
|
*.cm*
|
||||||
|
*.o
|
||||||
|
*~
|
||||||
|
*.swp
|
||||||
|
*.annot
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
|
||||||
|
# Directories generated by Ocamlbuild
|
||||||
|
_build
|
||||||
|
|
||||||
|
# IntelliJ files
|
||||||
|
scripts/.idea/
|
||||||
|
infer/tests/.idea/dictionaries
|
||||||
|
infer/tests/.idea/inspectionProfiles
|
||||||
|
infer/tests/.idea/tasks.xml
|
||||||
|
infer/tests/.idea/uiDesigner.xml
|
||||||
|
infer/tests/.idea/workspace.xml
|
||||||
|
infer/tests/.idea/misc.xml
|
||||||
|
infer/tests/.idea/runConfigurations
|
||||||
|
infer/tests/.idea/copyright/profiles_settings.xml
|
||||||
|
|
||||||
|
# Eclipse settings file
|
||||||
|
.project
|
||||||
|
.cproject
|
||||||
|
.paths
|
||||||
|
.pydevproject
|
||||||
|
.settings/
|
||||||
|
.classpath
|
||||||
|
|
||||||
|
# Arcanist
|
||||||
|
/arcanist/.phutil_module_cache
|
||||||
|
|
||||||
|
# MacOS generated files
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Directories and files generated by Infer
|
||||||
|
infer-out/
|
||||||
|
*.o.astlog
|
||||||
|
*.o.sh
|
||||||
|
|
||||||
|
# Directories generated by buck
|
||||||
|
buck-out/
|
||||||
|
.buckd/
|
||||||
|
|
||||||
|
#other
|
||||||
|
/infer/bin/InferAnalyze
|
||||||
|
/infer/bin/InferClang
|
||||||
|
/infer/bin/InferJava
|
||||||
|
/infer/bin/InferPrint
|
||||||
|
/infer/bin/Typeprop
|
||||||
|
/infer/src/backend/version.ml
|
||||||
|
infer/models/java/models/
|
||||||
|
infer/lib/java/models.jar
|
||||||
|
infer/models/java/bootclasspath
|
||||||
|
infer/lib/specs/c_models
|
||||||
|
infer/lib/specs/cpp_models
|
||||||
|
infer/lib/specs/objc_models
|
||||||
|
infer/lib/specs/clean_models
|
||||||
|
dependencies/clang-plugin/clang-plugin-version.done
|
||||||
|
include/
|
||||||
|
share/
|
||||||
|
|
||||||
|
#atdgen stubs
|
||||||
|
infer/src/backend/jsonbug_*
|
||||||
|
|
||||||
|
# intelliJ files
|
||||||
|
.idea
|
||||||
|
*.iml
|
||||||
|
|
||||||
|
/infer/src/backend/.projectSettings
|
||||||
|
infer/models/out/
|
||||||
|
|
||||||
|
/infer/_build-infer/
|
||||||
|
|
||||||
|
/infer/src/clang/clang_ast_j.ml
|
||||||
|
/infer/src/clang/clang_ast_j.mli
|
||||||
|
/infer/src/clang/clang_ast_proj.ml
|
||||||
|
/infer/src/clang/clang_ast_proj.mli
|
||||||
|
/infer/src/clang/clang_ast_t.ml
|
||||||
|
/infer/src/clang/clang_ast_t.mli
|
||||||
|
|
||||||
|
/infer/annotations/annotations.jar
|
@ -0,0 +1 @@
|
|||||||
|
We require contributors to sign our Contributor License Agreement. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla. If you have any questions, please drop us a line at cla@fb.com. Thanks!
|
@ -0,0 +1,30 @@
|
|||||||
|
BSD License
|
||||||
|
|
||||||
|
For Infer software
|
||||||
|
|
||||||
|
Copyright (c) 2013-, Facebook, Inc. All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name Facebook nor the names of its contributors may be used to
|
||||||
|
endorse or promote products derived from this software without specific
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -0,0 +1,33 @@
|
|||||||
|
Additional Grant of Patent Rights Version 2
|
||||||
|
|
||||||
|
"Software" means the Infer software distributed by Facebook, Inc.
|
||||||
|
|
||||||
|
Facebook, Inc. (“Facebook”) hereby grants to each recipient of the Software
|
||||||
|
(“you”) a perpetual, worldwide, royalty-free, non-exclusive, irrevocable
|
||||||
|
(subject to the termination provision below) license under any Necessary
|
||||||
|
Claims, to make, have made, use, sell, offer to sell, import, and otherwise
|
||||||
|
transfer the Software. For avoidance of doubt, no license is granted under
|
||||||
|
Facebook's rights in any patent claims that are infringed by (i) modifications
|
||||||
|
to the Software made by you or any third party or (ii) the Software in
|
||||||
|
combination with any software or other technology.
|
||||||
|
|
||||||
|
The license granted hereunder will terminate, automatically and without notice,
|
||||||
|
if you (or any of your subsidiaries, corporate affiliates or agents) initiate
|
||||||
|
directly or indirectly, or take a direct financial interest in, any Patent
|
||||||
|
Assertion: (i) against Facebook or any of its subsidiaries or corporate
|
||||||
|
affiliates, (ii) against any party if such Patent Assertion arises in whole or
|
||||||
|
in part from any software, technology, product or service of Facebook or any of
|
||||||
|
its subsidiaries or corporate affiliates, or (iii) against any party relating
|
||||||
|
to the Software. Notwithstanding the foregoing, if Facebook or any of its
|
||||||
|
subsidiaries or corporate affiliates files a lawsuit alleging patent
|
||||||
|
infringement against you in the first instance, and you respond by filing a
|
||||||
|
patent infringement counterclaim in that lawsuit against that party that is
|
||||||
|
unrelated to the Software, the license granted hereunder will not terminate
|
||||||
|
under section (i) of this paragraph due to such counterclaim.
|
||||||
|
|
||||||
|
A "Necessary Claim" is a claim of a patent owned by Facebook that is
|
||||||
|
necessarily infringed by the Software standing alone.
|
||||||
|
|
||||||
|
A "Patent Assertion" is any lawsuit or other action alleging direct, indirect,
|
||||||
|
or contributory infringement or inducement to infringe any patent, including a
|
||||||
|
cross-claim or counterclaim.
|
@ -0,0 +1,15 @@
|
|||||||
|
Infer
|
||||||
|
=====
|
||||||
|
|
||||||
|
Infer is a static analysis tool for Java and C / Objective C.
|
||||||
|
To see what it can do for you, check out the documentation at <http://facebook.github.io/infer/>.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
Read the [INSTALL.md](INSTALL.md) file for details on installing Infer.
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
Infer is BSD-licensed. We also provide an additional patent grant.
|
||||||
|
|
@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# This script installs the facebook-clang-plugins
|
||||||
|
#
|
||||||
|
# TODO (t5939566): ADD INSTRUCTIONS ON HOW TO CUSTOMIZE THE ENVVARS FOR
|
||||||
|
# THE INSTALLATION OF THE PLUGINS.
|
||||||
|
|
||||||
|
INFER_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
PLUGIN_DIR="$INFER_ROOT/../facebook-clang-plugin"
|
||||||
|
CLANG_EXEC="$PLUGIN_DIR/clang/bin/clang"
|
||||||
|
|
||||||
|
# check if clang is available
|
||||||
|
if ! $CLANG_EXEC --version 2>&1 | grep -q '3\.6'; then
|
||||||
|
echo "The required version of clang has not been found in $CLANG_EXEC" && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# install facebook-clang-plugins
|
||||||
|
pushd "$PLUGIN_DIR"
|
||||||
|
# prepare flags for the compilation on the Linux platform
|
||||||
|
platform="$(uname)"
|
||||||
|
if [ "$platform" == 'Linux' ]; then
|
||||||
|
export SDKPATH=""
|
||||||
|
export PATH="$PLUGIN_DIR/clang/bin:$PATH"
|
||||||
|
[ -z "$CC" ] && export CC="$PLUGIN_DIR/clang/bin/clang"
|
||||||
|
[ -z "$CXX" ] && export CXX="$PLUGIN_DIR/clang/bin/clang++"
|
||||||
|
[ -z "$CFLAGS" ] && export CFLAGS="-std=c++11 -fPIC"
|
||||||
|
[ -z "$LDFLAGS" ] && export LDFLAGS="-shared"
|
||||||
|
[ -z "$CLANG_PREFIX" ] && export CLANG_PREFIX="$PLUGIN_DIR/clang"
|
||||||
|
[ -z "$LLVM_INCLUDES" ] && export LLVM_INCLUDES="$PLUGIN_DIR/clang/include"
|
||||||
|
[ -z "$CLANG_INCLUDES" ] && export CLANG_INCLUDES="$LLVM_INCLUDES $CLANG_PREFIX/include"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# compile
|
||||||
|
make clean
|
||||||
|
make -C clang-ocaml clean
|
||||||
|
make
|
||||||
|
make -C clang-ocaml all build/clang_ast_proj.ml build/clang_ast_proj.mli
|
||||||
|
popd
|
||||||
|
|
||||||
|
# check YojsonASTExporter works with clang
|
||||||
|
echo "int main() { return 0; }" | \
|
||||||
|
$CLANG_EXEC -o /dev/null -x c \
|
||||||
|
-Xclang -load -Xclang $PLUGIN_DIR/libtooling/build/FacebookClangPlugin.dylib \
|
||||||
|
-Xclang -plugin -Xclang YojsonASTExporter -c - > /dev/null \
|
||||||
|
|| { echo "$CLANG_EXEC and the facebook-clang-plugins are not working.";
|
||||||
|
echo "Check you're using the right revision of clang, then retry"; exit 1; }
|
@ -0,0 +1 @@
|
|||||||
|
ab60f2578bf51a8b58afa63de7cee65d7ad891c9
|
@ -0,0 +1,17 @@
|
|||||||
|
java_library(
|
||||||
|
name = 'java_libraries',
|
||||||
|
deps=[
|
||||||
|
'//dependencies/java/guava:guava',
|
||||||
|
'//dependencies/java/junit:hamcrest',
|
||||||
|
'//dependencies/java/jackson:jackson',
|
||||||
|
'//dependencies/java/jsr-305:jsr-305',
|
||||||
|
'//dependencies/java/junit:junit',
|
||||||
|
'//dependencies/java/opencsv:opencsv'
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
project_config(
|
||||||
|
src_target = ':java_libraries',
|
||||||
|
)
|
@ -0,0 +1,7 @@
|
|||||||
|
prebuilt_jar(
|
||||||
|
name = 'guava',
|
||||||
|
binary_jar = 'guava-10.0.1-fork.jar',
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC'
|
||||||
|
]
|
||||||
|
)
|
Binary file not shown.
@ -0,0 +1,10 @@
|
|||||||
|
prebuilt_jar(
|
||||||
|
name = 'jackson',
|
||||||
|
binary_jar = 'jackson-2.2.3.jar',
|
||||||
|
deps = [
|
||||||
|
'//dependencies/java/guava:guava',
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC',
|
||||||
|
]
|
||||||
|
)
|
Binary file not shown.
@ -0,0 +1,8 @@
|
|||||||
|
prebuilt_jar(
|
||||||
|
name = 'jsr-305',
|
||||||
|
binary_jar = 'jsr305.jar',
|
||||||
|
source_jar = 'jsr305-src.jar',
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC',
|
||||||
|
],
|
||||||
|
)
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
prebuilt_jar(
|
||||||
|
name = 'hamcrest',
|
||||||
|
binary_jar = 'hamcrest-core-1.3.jar',
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
prebuilt_jar(
|
||||||
|
name = 'junit',
|
||||||
|
binary_jar = 'junit-4.11.jar',
|
||||||
|
deps = [
|
||||||
|
':hamcrest'
|
||||||
|
],
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
prebuilt_jar(
|
||||||
|
name = 'opencsv',
|
||||||
|
binary_jar = 'opencsv-2.3.jar',
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC'
|
||||||
|
]
|
||||||
|
)
|
@ -0,0 +1 @@
|
|||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
class Hello {
|
||||||
|
int test() {
|
||||||
|
String s = null;
|
||||||
|
return s.length();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface Hello: NSObject
|
||||||
|
@property NSString* s;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation Hello
|
||||||
|
NSString* m() {
|
||||||
|
Hello* hello = nil;
|
||||||
|
return hello->_s;
|
||||||
|
}
|
||||||
|
@end
|
@ -0,0 +1,39 @@
|
|||||||
|
This directory contains small examples to play with Infer. They each exhibit
|
||||||
|
one simple programming error that is caught by Infer.
|
||||||
|
|
||||||
|
Contents
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Hello.java: try this example by running
|
||||||
|
infer -- javac Hello.java
|
||||||
|
|
||||||
|
- Hello.m: try this example by running
|
||||||
|
infer -- clang -c Hello.m
|
||||||
|
|
||||||
|
- hello.c: try this example by running
|
||||||
|
infer -- gcc -c hello.c
|
||||||
|
|
||||||
|
In this case, note that Infer captures the gcc command and runs
|
||||||
|
clang instead to parse C files. Thus you may get compiler errors and
|
||||||
|
warnings that differ from gcc's.
|
||||||
|
|
||||||
|
- android_hello/: a sample Android app. Try this example by running
|
||||||
|
infer -- ./gradlew build
|
||||||
|
|
||||||
|
Make sure that you have the Android SDK 22 installed and up to date, and in
|
||||||
|
particular the "Android SDK Build-tools" and "Android Support Repository".
|
||||||
|
|
||||||
|
- ios_hello/: a sample iOS app. Try this example by running
|
||||||
|
infer -- xcodebuild -target HelloWorldApp -configuration Debug -sdk iphonesimulator
|
||||||
|
|
||||||
|
- c_hello/: a sample make-based C project. Try this example by running
|
||||||
|
infer -- make
|
||||||
|
|
||||||
|
|
||||||
|
Note
|
||||||
|
----
|
||||||
|
|
||||||
|
The infer toplevel command must be in your PATH for the commands above to
|
||||||
|
succeed. Otherwise, modify the commands to use the correct path to infer, eg
|
||||||
|
../infer/bin/infer -- javac Hello.java
|
||||||
|
|
@ -0,0 +1,6 @@
|
|||||||
|
.gradle
|
||||||
|
/local.properties
|
||||||
|
/.idea/workspace.xml
|
||||||
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
|
/build
|
@ -0,0 +1 @@
|
|||||||
|
/build
|
@ -0,0 +1,25 @@
|
|||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 22
|
||||||
|
buildToolsVersion "22.0.1"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "infer.inferandroidexample"
|
||||||
|
minSdkVersion 8
|
||||||
|
targetSdkVersion 22
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
compile 'com.android.support:appcompat-v7:22.0.0'
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# By default, the flags in this file are appended to flags specified
|
||||||
|
# in /Users/irp/android-sdk-macosx/tools/proguard/proguard-android.txt
|
||||||
|
# You can edit the include path and order by changing the proguardFiles
|
||||||
|
# directive in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# Add any project specific keep options here:
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
@ -0,0 +1,13 @@
|
|||||||
|
package infer.inferandroidexample;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
import android.test.ApplicationTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
|
||||||
|
*/
|
||||||
|
public class ApplicationTest extends ApplicationTestCase<Application> {
|
||||||
|
public ApplicationTest() {
|
||||||
|
super(Application.class);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="infer.inferandroidexample" >
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@drawable/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme" >
|
||||||
|
<activity
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
@ -0,0 +1,63 @@
|
|||||||
|
package infer.inferandroidexample;
|
||||||
|
|
||||||
|
import android.support.v7.app.ActionBarActivity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
|
||||||
|
public class MainActivity extends ActionBarActivity {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
String s = getDay();
|
||||||
|
int length = s.length();
|
||||||
|
writeToFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getDay() {
|
||||||
|
if (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) == Calendar.WEDNESDAY) {
|
||||||
|
return "Wednesday";
|
||||||
|
} else return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeToFile() {
|
||||||
|
byte[] arr = {1, 2, 3};
|
||||||
|
FileOutputStream fis;
|
||||||
|
try {
|
||||||
|
fis = new FileOutputStream("file.txt");
|
||||||
|
fis.write(arr);
|
||||||
|
fis.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
//Deal with exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
|
getMenuInflater().inflate(R.menu.menu_main, menu);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
// Handle action bar item clicks here. The action bar will
|
||||||
|
// automatically handle clicks on the Home/Up button, so long
|
||||||
|
// as you specify a parent activity in AndroidManifest.xml.
|
||||||
|
int id = item.getItemId();
|
||||||
|
|
||||||
|
//noinspection SimplifiableIfStatement
|
||||||
|
if (id == R.id.action_settings) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 9.2 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 19 KiB |
@ -0,0 +1,11 @@
|
|||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||||
|
android:paddingTop="@dimen/activity_vertical_margin"
|
||||||
|
android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
|
||||||
|
|
||||||
|
<TextView android:text="@string/hello_world" android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
@ -0,0 +1,6 @@
|
|||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
|
||||||
|
<item android:id="@+id/action_settings" android:title="@string/action_settings"
|
||||||
|
android:orderInCategory="100" app:showAsAction="never" />
|
||||||
|
</menu>
|
@ -0,0 +1,6 @@
|
|||||||
|
<resources>
|
||||||
|
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
|
||||||
|
(such as screen margins) for screens with more than 820dp of available width. This
|
||||||
|
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
|
||||||
|
<dimen name="activity_horizontal_margin">64dp</dimen>
|
||||||
|
</resources>
|
@ -0,0 +1,5 @@
|
|||||||
|
<resources>
|
||||||
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
</resources>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<string name="app_name">InferAndroidExample</string>
|
||||||
|
<string name="hello_world">Hello world!</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
|
||||||
|
</resources>
|
@ -0,0 +1,8 @@
|
|||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
@ -0,0 +1,19 @@
|
|||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:1.0.0'
|
||||||
|
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
// in the individual module build.gradle files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
# Project-wide Gradle settings.
|
||||||
|
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
# Default value: -Xmx10248m -XX:MaxPermSize=256m
|
||||||
|
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
|
||||||
|
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
Binary file not shown.
@ -0,0 +1,6 @@
|
|||||||
|
#Wed Apr 10 15:27:10 PDT 2013
|
||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
|
@ -0,0 +1,164 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
##
|
||||||
|
## Gradle start up script for UN*X
|
||||||
|
##
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS=""
|
||||||
|
|
||||||
|
APP_NAME="Gradle"
|
||||||
|
APP_BASE_NAME=`basename "$0"`
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD="maximum"
|
||||||
|
|
||||||
|
warn ( ) {
|
||||||
|
echo "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die ( ) {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
case "`uname`" in
|
||||||
|
CYGWIN* )
|
||||||
|
cygwin=true
|
||||||
|
;;
|
||||||
|
Darwin* )
|
||||||
|
darwin=true
|
||||||
|
;;
|
||||||
|
MINGW* )
|
||||||
|
msys=true
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||||
|
if $cygwin ; then
|
||||||
|
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
PRG="$0"
|
||||||
|
# Need this for relative symlinks.
|
||||||
|
while [ -h "$PRG" ] ; do
|
||||||
|
ls=`ls -ld "$PRG"`
|
||||||
|
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||||
|
if expr "$link" : '/.*' > /dev/null; then
|
||||||
|
PRG="$link"
|
||||||
|
else
|
||||||
|
PRG=`dirname "$PRG"`"/$link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
SAVED="`pwd`"
|
||||||
|
cd "`dirname \"$PRG\"`/" >&-
|
||||||
|
APP_HOME="`pwd -P`"
|
||||||
|
cd "$SAVED" >&-
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||||
|
else
|
||||||
|
JAVACMD="$JAVA_HOME/bin/java"
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD="java"
|
||||||
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
||||||
|
MAX_FD_LIMIT=`ulimit -H -n`
|
||||||
|
if [ $? -eq 0 ] ; then
|
||||||
|
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||||
|
MAX_FD="$MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
ulimit -n $MAX_FD
|
||||||
|
if [ $? -ne 0 ] ; then
|
||||||
|
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Darwin, add options to specify how the application appears in the dock
|
||||||
|
if $darwin; then
|
||||||
|
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For Cygwin, switch paths to Windows format before running java
|
||||||
|
if $cygwin ; then
|
||||||
|
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||||
|
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||||
|
|
||||||
|
# We build the pattern for arguments to be converted via cygpath
|
||||||
|
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||||
|
SEP=""
|
||||||
|
for dir in $ROOTDIRSRAW ; do
|
||||||
|
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||||
|
SEP="|"
|
||||||
|
done
|
||||||
|
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||||
|
# Add a user-defined pattern to the cygpath arguments
|
||||||
|
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||||
|
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||||
|
fi
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
i=0
|
||||||
|
for arg in "$@" ; do
|
||||||
|
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||||
|
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||||
|
|
||||||
|
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||||
|
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||||
|
else
|
||||||
|
eval `echo args$i`="\"$arg\""
|
||||||
|
fi
|
||||||
|
i=$((i+1))
|
||||||
|
done
|
||||||
|
case $i in
|
||||||
|
(0) set -- ;;
|
||||||
|
(1) set -- "$args0" ;;
|
||||||
|
(2) set -- "$args0" "$args1" ;;
|
||||||
|
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||||
|
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||||
|
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||||
|
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||||
|
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||||
|
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||||
|
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
||||||
|
function splitJvmOpts() {
|
||||||
|
JVM_OPTS=("$@")
|
||||||
|
}
|
||||||
|
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
||||||
|
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
||||||
|
|
||||||
|
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
@ -0,0 +1 @@
|
|||||||
|
include ':app'
|
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
SOURCES = $(shell ls *.c)
|
||||||
|
OBJECTS = $(SOURCES:.c=.o)
|
||||||
|
|
||||||
|
all: $(OBJECTS)
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
${CC} -c $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(OBJECTS)
|
@ -0,0 +1,60 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
struct Person {
|
||||||
|
int age;
|
||||||
|
int height;
|
||||||
|
int weight;
|
||||||
|
};
|
||||||
|
|
||||||
|
int simple_null_pointer() {
|
||||||
|
struct Person *max = 0;
|
||||||
|
return max->age;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Person *Person_create(int age, int height, int weight) {
|
||||||
|
struct Person *who = 0;
|
||||||
|
return who;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_age(struct Person *who) {
|
||||||
|
return who->age;
|
||||||
|
}
|
||||||
|
|
||||||
|
int null_pointer_interproc() {
|
||||||
|
struct Person *joe = Person_create(32, 64, 140);
|
||||||
|
return get_age(joe);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fileNotClosed()
|
||||||
|
{
|
||||||
|
int fd = open("hi.txt", O_WRONLY | O_CREAT | O_TRUNC, 0600);
|
||||||
|
if (fd != -1) {
|
||||||
|
char buffer[256];
|
||||||
|
// We can easily batch that by separating with space
|
||||||
|
write(fd, buffer, strlen(buffer));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simple_leak() {
|
||||||
|
int *p;
|
||||||
|
p = (int*) malloc(sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
void common_realloc_leak() {
|
||||||
|
int *p, *q;
|
||||||
|
p = (int*) malloc(sizeof(int));
|
||||||
|
q = (int*) realloc(p, sizeof(int) * 42);
|
||||||
|
// if realloc fails, then p becomes unreachable
|
||||||
|
if (q != NULL) free(q);
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
int *s = NULL;
|
||||||
|
*s = 42;
|
||||||
|
}
|
@ -0,0 +1,433 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 46;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
124F6C531B0CDAE400C16385 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 124F6C521B0CDAE400C16385 /* main.m */; };
|
||||||
|
124F6C561B0CDAE400C16385 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 124F6C551B0CDAE400C16385 /* AppDelegate.m */; };
|
||||||
|
124F6C591B0CDAE400C16385 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 124F6C581B0CDAE400C16385 /* ViewController.m */; };
|
||||||
|
124F6C5C1B0CDAE400C16385 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 124F6C5A1B0CDAE400C16385 /* Main.storyboard */; };
|
||||||
|
124F6C5E1B0CDAE400C16385 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 124F6C5D1B0CDAE400C16385 /* Images.xcassets */; };
|
||||||
|
124F6C611B0CDAE400C16385 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 124F6C5F1B0CDAE400C16385 /* LaunchScreen.xib */; };
|
||||||
|
124F6C6D1B0CDAE400C16385 /* HelloWorldAppTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 124F6C6C1B0CDAE400C16385 /* HelloWorldAppTests.m */; };
|
||||||
|
124F6C771B0CED9B00C16385 /* Hello.m in Sources */ = {isa = PBXBuildFile; fileRef = 124F6C761B0CED9B00C16385 /* Hello.m */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
124F6C671B0CDAE400C16385 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 124F6C451B0CDAE400C16385 /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 124F6C4C1B0CDAE400C16385;
|
||||||
|
remoteInfo = HelloWorldApp;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
124F6C4D1B0CDAE400C16385 /* HelloWorldApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorldApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
124F6C511B0CDAE400C16385 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
124F6C521B0CDAE400C16385 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
|
124F6C541B0CDAE400C16385 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||||
|
124F6C551B0CDAE400C16385 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||||
|
124F6C571B0CDAE400C16385 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||||
|
124F6C581B0CDAE400C16385 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
|
||||||
|
124F6C5B1B0CDAE400C16385 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
|
124F6C5D1B0CDAE400C16385 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||||
|
124F6C601B0CDAE400C16385 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
|
||||||
|
124F6C661B0CDAE400C16385 /* HelloWorldAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HelloWorldAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
124F6C6B1B0CDAE400C16385 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
124F6C6C1B0CDAE400C16385 /* HelloWorldAppTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HelloWorldAppTests.m; sourceTree = "<group>"; };
|
||||||
|
124F6C761B0CED9B00C16385 /* Hello.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Hello.m; sourceTree = "<group>"; };
|
||||||
|
124F6C781B0CEDAF00C16385 /* Hello.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Hello.h; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
124F6C4A1B0CDAE400C16385 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
124F6C631B0CDAE400C16385 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
124F6C441B0CDAE400C16385 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
124F6C4F1B0CDAE400C16385 /* HelloWorldApp */,
|
||||||
|
124F6C691B0CDAE400C16385 /* HelloWorldAppTests */,
|
||||||
|
124F6C4E1B0CDAE400C16385 /* Products */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
124F6C4E1B0CDAE400C16385 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
124F6C4D1B0CDAE400C16385 /* HelloWorldApp.app */,
|
||||||
|
124F6C661B0CDAE400C16385 /* HelloWorldAppTests.xctest */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
124F6C4F1B0CDAE400C16385 /* HelloWorldApp */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
124F6C541B0CDAE400C16385 /* AppDelegate.h */,
|
||||||
|
124F6C551B0CDAE400C16385 /* AppDelegate.m */,
|
||||||
|
124F6C571B0CDAE400C16385 /* ViewController.h */,
|
||||||
|
124F6C581B0CDAE400C16385 /* ViewController.m */,
|
||||||
|
124F6C5A1B0CDAE400C16385 /* Main.storyboard */,
|
||||||
|
124F6C5D1B0CDAE400C16385 /* Images.xcassets */,
|
||||||
|
124F6C5F1B0CDAE400C16385 /* LaunchScreen.xib */,
|
||||||
|
124F6C501B0CDAE400C16385 /* Supporting Files */,
|
||||||
|
124F6C761B0CED9B00C16385 /* Hello.m */,
|
||||||
|
124F6C781B0CEDAF00C16385 /* Hello.h */,
|
||||||
|
);
|
||||||
|
path = HelloWorldApp;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
124F6C501B0CDAE400C16385 /* Supporting Files */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
124F6C511B0CDAE400C16385 /* Info.plist */,
|
||||||
|
124F6C521B0CDAE400C16385 /* main.m */,
|
||||||
|
);
|
||||||
|
name = "Supporting Files";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
124F6C691B0CDAE400C16385 /* HelloWorldAppTests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
124F6C6C1B0CDAE400C16385 /* HelloWorldAppTests.m */,
|
||||||
|
124F6C6A1B0CDAE400C16385 /* Supporting Files */,
|
||||||
|
);
|
||||||
|
path = HelloWorldAppTests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
124F6C6A1B0CDAE400C16385 /* Supporting Files */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
124F6C6B1B0CDAE400C16385 /* Info.plist */,
|
||||||
|
);
|
||||||
|
name = "Supporting Files";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
124F6C4C1B0CDAE400C16385 /* HelloWorldApp */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 124F6C701B0CDAE400C16385 /* Build configuration list for PBXNativeTarget "HelloWorldApp" */;
|
||||||
|
buildPhases = (
|
||||||
|
124F6C491B0CDAE400C16385 /* Sources */,
|
||||||
|
124F6C4A1B0CDAE400C16385 /* Frameworks */,
|
||||||
|
124F6C4B1B0CDAE400C16385 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = HelloWorldApp;
|
||||||
|
productName = HelloWorldApp;
|
||||||
|
productReference = 124F6C4D1B0CDAE400C16385 /* HelloWorldApp.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
124F6C651B0CDAE400C16385 /* HelloWorldAppTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 124F6C731B0CDAE400C16385 /* Build configuration list for PBXNativeTarget "HelloWorldAppTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
124F6C621B0CDAE400C16385 /* Sources */,
|
||||||
|
124F6C631B0CDAE400C16385 /* Frameworks */,
|
||||||
|
124F6C641B0CDAE400C16385 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
124F6C681B0CDAE400C16385 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = HelloWorldAppTests;
|
||||||
|
productName = HelloWorldAppTests;
|
||||||
|
productReference = 124F6C661B0CDAE400C16385 /* HelloWorldAppTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
124F6C451B0CDAE400C16385 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
LastUpgradeCheck = 0620;
|
||||||
|
ORGANIZATIONNAME = "Dulma Rodriguez";
|
||||||
|
TargetAttributes = {
|
||||||
|
124F6C4C1B0CDAE400C16385 = {
|
||||||
|
CreatedOnToolsVersion = 6.2;
|
||||||
|
};
|
||||||
|
124F6C651B0CDAE400C16385 = {
|
||||||
|
CreatedOnToolsVersion = 6.2;
|
||||||
|
TestTargetID = 124F6C4C1B0CDAE400C16385;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 124F6C481B0CDAE400C16385 /* Build configuration list for PBXProject "HelloWorldApp" */;
|
||||||
|
compatibilityVersion = "Xcode 3.2";
|
||||||
|
developmentRegion = English;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 124F6C441B0CDAE400C16385;
|
||||||
|
productRefGroup = 124F6C4E1B0CDAE400C16385 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
124F6C4C1B0CDAE400C16385 /* HelloWorldApp */,
|
||||||
|
124F6C651B0CDAE400C16385 /* HelloWorldAppTests */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
124F6C4B1B0CDAE400C16385 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
124F6C5C1B0CDAE400C16385 /* Main.storyboard in Resources */,
|
||||||
|
124F6C611B0CDAE400C16385 /* LaunchScreen.xib in Resources */,
|
||||||
|
124F6C5E1B0CDAE400C16385 /* Images.xcassets in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
124F6C641B0CDAE400C16385 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
124F6C491B0CDAE400C16385 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
124F6C591B0CDAE400C16385 /* ViewController.m in Sources */,
|
||||||
|
124F6C561B0CDAE400C16385 /* AppDelegate.m in Sources */,
|
||||||
|
124F6C771B0CED9B00C16385 /* Hello.m in Sources */,
|
||||||
|
124F6C531B0CDAE400C16385 /* main.m in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
124F6C621B0CDAE400C16385 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
124F6C6D1B0CDAE400C16385 /* HelloWorldAppTests.m in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
124F6C681B0CDAE400C16385 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 124F6C4C1B0CDAE400C16385 /* HelloWorldApp */;
|
||||||
|
targetProxy = 124F6C671B0CDAE400C16385 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
124F6C5A1B0CDAE400C16385 /* Main.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
124F6C5B1B0CDAE400C16385 /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
124F6C5F1B0CDAE400C16385 /* LaunchScreen.xib */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
124F6C601B0CDAE400C16385 /* Base */,
|
||||||
|
);
|
||||||
|
name = LaunchScreen.xib;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
124F6C6E1B0CDAE400C16385 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
124F6C6F1B0CDAE400C16385 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
124F6C711B0CDAE400C16385 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
INFOPLIST_FILE = HelloWorldApp/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
124F6C721B0CDAE400C16385 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
INFOPLIST_FILE = HelloWorldApp/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
124F6C741B0CDAE400C16385 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
INFOPLIST_FILE = HelloWorldAppTests/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorldApp.app/HelloWorldApp";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
124F6C751B0CDAE400C16385 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
"$(SDKROOT)/Developer/Library/Frameworks",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
INFOPLIST_FILE = HelloWorldAppTests/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/HelloWorldApp.app/HelloWorldApp";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
124F6C481B0CDAE400C16385 /* Build configuration list for PBXProject "HelloWorldApp" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
124F6C6E1B0CDAE400C16385 /* Debug */,
|
||||||
|
124F6C6F1B0CDAE400C16385 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
124F6C701B0CDAE400C16385 /* Build configuration list for PBXNativeTarget "HelloWorldApp" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
124F6C711B0CDAE400C16385 /* Debug */,
|
||||||
|
124F6C721B0CDAE400C16385 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
};
|
||||||
|
124F6C731B0CDAE400C16385 /* Build configuration list for PBXNativeTarget "HelloWorldAppTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
124F6C741B0CDAE400C16385 /* Debug */,
|
||||||
|
124F6C751B0CDAE400C16385 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = 124F6C451B0CDAE400C16385 /* Project object */;
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:HelloWorldApp.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
Binary file not shown.
@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Bucket
|
||||||
|
type = "1"
|
||||||
|
version = "2.0">
|
||||||
|
<Breakpoints>
|
||||||
|
<BreakpointProxy
|
||||||
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
|
<BreakpointContent
|
||||||
|
shouldBeEnabled = "Yes"
|
||||||
|
ignoreCount = "0"
|
||||||
|
continueAfterRunningActions = "No"
|
||||||
|
filePath = "HelloWorldApp/AppDelegate.m"
|
||||||
|
timestampString = "453837074.323482"
|
||||||
|
startingColumnNumber = "9223372036854775807"
|
||||||
|
endingColumnNumber = "9223372036854775807"
|
||||||
|
startingLineNumber = "30"
|
||||||
|
endingLineNumber = "30"
|
||||||
|
landmarkName = "-resource_leak_bug"
|
||||||
|
landmarkType = "5">
|
||||||
|
</BreakpointContent>
|
||||||
|
</BreakpointProxy>
|
||||||
|
</Breakpoints>
|
||||||
|
</Bucket>
|
@ -0,0 +1,112 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "0620"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "124F6C4C1B0CDAE400C16385"
|
||||||
|
BuildableName = "HelloWorldApp.app"
|
||||||
|
BlueprintName = "HelloWorldApp"
|
||||||
|
ReferencedContainer = "container:HelloWorldApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "NO"
|
||||||
|
buildForArchiving = "NO"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "124F6C651B0CDAE400C16385"
|
||||||
|
BuildableName = "HelloWorldAppTests.xctest"
|
||||||
|
BlueprintName = "HelloWorldAppTests"
|
||||||
|
ReferencedContainer = "container:HelloWorldApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "124F6C651B0CDAE400C16385"
|
||||||
|
BuildableName = "HelloWorldAppTests.xctest"
|
||||||
|
BlueprintName = "HelloWorldAppTests"
|
||||||
|
ReferencedContainer = "container:HelloWorldApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "124F6C4C1B0CDAE400C16385"
|
||||||
|
BuildableName = "HelloWorldApp.app"
|
||||||
|
BlueprintName = "HelloWorldApp"
|
||||||
|
ReferencedContainer = "container:HelloWorldApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "124F6C4C1B0CDAE400C16385"
|
||||||
|
BuildableName = "HelloWorldApp.app"
|
||||||
|
BlueprintName = "HelloWorldApp"
|
||||||
|
ReferencedContainer = "container:HelloWorldApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "124F6C4C1B0CDAE400C16385"
|
||||||
|
BuildableName = "HelloWorldApp.app"
|
||||||
|
BlueprintName = "HelloWorldApp"
|
||||||
|
ReferencedContainer = "container:HelloWorldApp.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>SchemeUserState</key>
|
||||||
|
<dict>
|
||||||
|
<key>HelloWorldApp.xcscheme</key>
|
||||||
|
<dict>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>SuppressBuildableAutocreation</key>
|
||||||
|
<dict>
|
||||||
|
<key>124F6C4C1B0CDAE400C16385</key>
|
||||||
|
<dict>
|
||||||
|
<key>primary</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>124F6C651B0CDAE400C16385</key>
|
||||||
|
<dict>
|
||||||
|
<key>primary</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// AppDelegate.h
|
||||||
|
// HelloWorldApp
|
||||||
|
//
|
||||||
|
// Created by Dulma Rodriguez on 20/05/2015.
|
||||||
|
// Copyright (c) 2015 Dulma Rodriguez. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||||
|
|
||||||
|
@property (strong, nonatomic) UIWindow *window;
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
@ -0,0 +1,78 @@
|
|||||||
|
//
|
||||||
|
// AppDelegate.m
|
||||||
|
// HelloWorldApp
|
||||||
|
//
|
||||||
|
// Created by Dulma Rodriguez on 20/05/2015.
|
||||||
|
// Copyright (c) 2015 Dulma Rodriguez. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "AppDelegate.h"
|
||||||
|
#import "Hello.h"
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface AppDelegate ()
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation AppDelegate
|
||||||
|
|
||||||
|
-(void) memory_leak_bug {
|
||||||
|
CGPathRef shadowPath = CGPathCreateWithRect(self.inputView.bounds, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) resource_leak_bug {
|
||||||
|
FILE *fp;
|
||||||
|
fp=fopen("c:\\test.txt", "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void) parameter_not_null_checked_block_bug:(void (^)())callback {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSArray*) npe_in_array_literal_bug {
|
||||||
|
NSString *str = nil;
|
||||||
|
return @[@"horse", str, @"dolphin"];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSArray*) premature_nil_termination_argument_bug {
|
||||||
|
NSString *str = nil;
|
||||||
|
return [NSArray arrayWithObjects: @"horse", str, @"dolphin", nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
||||||
|
// Override point for customization after application launch.
|
||||||
|
Hello *hello = [Hello new];
|
||||||
|
[hello null_dereference_bug];
|
||||||
|
[self memory_leak_bug];
|
||||||
|
[self resource_leak_bug];
|
||||||
|
[hello parameter_not_null_checked_bug:nil];
|
||||||
|
[self parameter_not_null_checked_block_bug:nil];
|
||||||
|
[hello ivar_not_nullable_bug:nil];
|
||||||
|
[self npe_in_array_literal_bug];
|
||||||
|
[self premature_nil_termination_argument_bug];
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||||
|
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
|
||||||
|
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidEnterBackground:(UIApplication *)application {
|
||||||
|
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
|
||||||
|
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillEnterForeground:(UIApplication *)application {
|
||||||
|
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||||
|
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationWillTerminate:(UIApplication *)application {
|
||||||
|
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
|
||||||
|
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
|
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Dulma Rodriguez. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
|
||||||
|
<rect key="frame" x="20" y="439" width="441" height="21"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="HelloWorldApp" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
|
||||||
|
<rect key="frame" x="20" y="140" width="441" height="43"/>
|
||||||
|
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
|
||||||
|
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
|
||||||
|
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
|
||||||
|
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
|
||||||
|
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
||||||
|
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
|
||||||
|
</constraints>
|
||||||
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
|
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
||||||
|
<point key="canvasLocation" x="548" y="455"/>
|
||||||
|
</view>
|
||||||
|
</objects>
|
||||||
|
</document>
|
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="vXZ-lx-hvc">
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="ufC-wZ-h7g">
|
||||||
|
<objects>
|
||||||
|
<viewController id="vXZ-lx-hvc" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="jyV-Pf-zRb"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="2fi-mo-0CV"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="kh9-bI-dsS">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="x5A-6p-PRh" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// Hello.h
|
||||||
|
// HelloWorldApp
|
||||||
|
//
|
||||||
|
// Created by Dulma Rodriguez on 20/05/2015.
|
||||||
|
// Copyright (c) 2015 Dulma Rodriguez. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@interface Hello : NSObject
|
||||||
|
|
||||||
|
@property (strong) NSString* s;
|
||||||
|
@property (strong) Hello* hello;
|
||||||
|
|
||||||
|
-(Hello*) return_hello;
|
||||||
|
|
||||||
|
-(NSString*) null_dereference_bug;
|
||||||
|
|
||||||
|
-(NSString*) ivar_not_nullable_bug:(Hello*) hello;
|
||||||
|
|
||||||
|
-(NSString*) parameter_not_null_checked_bug:(Hello*) hello;
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// Hello.m
|
||||||
|
// HelloWorldApp
|
||||||
|
//
|
||||||
|
// Created by Dulma Rodriguez on 20/05/2015.
|
||||||
|
// Copyright (c) 2015 Dulma Rodriguez. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import "Hello.h"
|
||||||
|
|
||||||
|
@implementation Hello
|
||||||
|
|
||||||
|
-(Hello*) return_hello {
|
||||||
|
return [Hello new];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSString*) null_dereference_bug {
|
||||||
|
Hello *hello = nil;
|
||||||
|
return hello->_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSString*) ivar_not_nullable_bug:(Hello*) hello {
|
||||||
|
Hello* ret_hello = [hello->_hello return_hello];
|
||||||
|
return ret_hello->_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSString*) parameter_not_null_checked_bug:(Hello*) hello {
|
||||||
|
Hello *ret_hello = [hello return_hello];
|
||||||
|
return ret_hello->_s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "29x29",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "29x29",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "40x40",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "40x40",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "60x60",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"size" : "60x60",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.facebook.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>armv7</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// ViewController.h
|
||||||
|
// HelloWorldApp
|
||||||
|
//
|
||||||
|
// Created by Dulma Rodriguez on 20/05/2015.
|
||||||
|
// Copyright (c) 2015 Dulma Rodriguez. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
@interface ViewController : UIViewController
|
||||||
|
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// ViewController.m
|
||||||
|
// HelloWorldApp
|
||||||
|
//
|
||||||
|
// Created by Dulma Rodriguez on 20/05/2015.
|
||||||
|
// Copyright (c) 2015 Dulma Rodriguez. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "ViewController.h"
|
||||||
|
|
||||||
|
@interface ViewController ()
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ViewController
|
||||||
|
|
||||||
|
- (void)viewDidLoad {
|
||||||
|
[super viewDidLoad];
|
||||||
|
// Do any additional setup after loading the view, typically from a nib.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)didReceiveMemoryWarning {
|
||||||
|
[super didReceiveMemoryWarning];
|
||||||
|
// Dispose of any resources that can be recreated.
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// main.m
|
||||||
|
// HelloWorldApp
|
||||||
|
//
|
||||||
|
// Created by Dulma Rodriguez on 20/05/2015.
|
||||||
|
// Copyright (c) 2015 Dulma Rodriguez. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import "AppDelegate.h"
|
||||||
|
|
||||||
|
int main(int argc, char * argv[]) {
|
||||||
|
@autoreleasepool {
|
||||||
|
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// HelloWorldAppTests.m
|
||||||
|
// HelloWorldAppTests
|
||||||
|
//
|
||||||
|
// Created by Dulma Rodriguez on 20/05/2015.
|
||||||
|
// Copyright (c) 2015 Dulma Rodriguez. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <XCTest/XCTest.h>
|
||||||
|
|
||||||
|
@interface HelloWorldAppTests : XCTestCase
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation HelloWorldAppTests
|
||||||
|
|
||||||
|
- (void)setUp {
|
||||||
|
[super setUp];
|
||||||
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)tearDown {
|
||||||
|
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||||||
|
[super tearDown];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testExample {
|
||||||
|
// This is an example of a functional test case.
|
||||||
|
XCTAssert(YES, @"Pass");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testPerformanceExample {
|
||||||
|
// This is an example of a performance test case.
|
||||||
|
[self measureBlock:^{
|
||||||
|
// Put the code you want to measure the time of here.
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>com.facebook.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>BNDL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -0,0 +1,4 @@
|
|||||||
|
S src/**
|
||||||
|
B _build-infer/**
|
||||||
|
PKG sawja
|
||||||
|
PKG atdgen
|
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>EdgNative</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>Ocaml.ocamlMakefileBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>ocaml.ocamlnatureMakefile</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
@ -0,0 +1,25 @@
|
|||||||
|
SHELL := /bin/bash
|
||||||
|
CWD = $(shell pwd)
|
||||||
|
|
||||||
|
ANNOTATIONS = annotations
|
||||||
|
MODELS = models
|
||||||
|
SRCDIR = src
|
||||||
|
|
||||||
|
|
||||||
|
.PHONY: clean clang java models
|
||||||
|
|
||||||
|
all: clang java
|
||||||
|
|
||||||
|
java:
|
||||||
|
make -C $(SRCDIR) java
|
||||||
|
make -C $(MODELS) java
|
||||||
|
make -C $(ANNOTATIONS)
|
||||||
|
|
||||||
|
clang:
|
||||||
|
make -C $(SRCDIR) clang
|
||||||
|
make -C $(MODELS) clang
|
||||||
|
|
||||||
|
clean:
|
||||||
|
make -C $(SRCDIR) clean
|
||||||
|
make -C $(MODELS) clean
|
||||||
|
make -C $(ANNOTATIONS) clean
|
@ -0,0 +1,7 @@
|
|||||||
|
prebuilt_jar(
|
||||||
|
name = 'annotations',
|
||||||
|
binary_jar = 'annotations.jar',
|
||||||
|
visibility = [
|
||||||
|
'PUBLIC',
|
||||||
|
]
|
||||||
|
)
|
@ -0,0 +1,13 @@
|
|||||||
|
DEPENDENCIES = ../../dependencies
|
||||||
|
JSR_JAR = $(DEPENDENCIES)/java/jsr-305/jsr305.jar
|
||||||
|
CLASSES_OUT = classes
|
||||||
|
SOURCES = `find . -name "*.java"`
|
||||||
|
|
||||||
|
all:
|
||||||
|
mkdir -p classes
|
||||||
|
javac -cp $(JSR_JAR) $(SOURCES)
|
||||||
|
jar cvf annotations.jar $(SOURCES) `find . -name "*.class"`
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rvf `find . -name "*.class"`
|
||||||
|
rm -rvf annotations.jar
|
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class Assertions {
|
||||||
|
|
||||||
|
public static <T> T assumeNotNull(@Nullable T object) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T assumeNotNull(@Nullable T object, String explanation) {
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T assertNotNull(@Nullable T object) {
|
||||||
|
if (object == null) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T assertNotNull(@Nullable T object, String explanation) {
|
||||||
|
if (object == null) {
|
||||||
|
throw new AssertionError(explanation);
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getAssumingNotNull(List<T> list, int index) {
|
||||||
|
return list.get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T getAssertingNotNull(List<T> list, int index) {
|
||||||
|
assertCondition(0 <= index && index < list.size());
|
||||||
|
return assertNotNull(list.get(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> V getAssumingNotNull(Map<K, V> map, K key) {
|
||||||
|
return map.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> V getAssertingNotNull(Map<K, V> map, K key) {
|
||||||
|
assertCondition(map.containsKey(key));
|
||||||
|
return assertNotNull(map.get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assumeCondition(boolean condition) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assumeCondition(boolean condition, String explanation) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertCondition(boolean condition) {
|
||||||
|
if (!condition) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void assertCondition(boolean condition, String explanation) {
|
||||||
|
if (!condition) {
|
||||||
|
throw new AssertionError(explanation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssertionError assertUnreachable() {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssertionError assertUnreachable(String explanation) {
|
||||||
|
throw new AssertionError(explanation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AssertionError assertUnreachable(Exception exception) {
|
||||||
|
throw new AssertionError(exception);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method annotated with @Initializer should always be be called before the object is used.
|
||||||
|
* Users of the class and static checkers must enforce, and can rely on, this invariant.
|
||||||
|
* Examples include methods called indirectly by the constructor, protocols of init-then-use
|
||||||
|
* where some values are initialized after construction but before the first use,
|
||||||
|
* and builder classes where an object initialization must complete before build() is called.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
|
||||||
|
public @interface Initializer {}
|
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
|
||||||
|
public @interface Mutable {}
|
@ -0,0 +1,18 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class field, or method return/parameter type, of Optional type is annotated @Present
|
||||||
|
* to indicate that its value cannot be absent.
|
||||||
|
* Users of the method/field and static checkers must enforce, and can rely on, this invariant.
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR,
|
||||||
|
ElementType.METHOD, ElementType.PARAMETER})
|
||||||
|
public @interface Present {}
|
@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({
|
||||||
|
ElementType.CONSTRUCTOR,
|
||||||
|
ElementType.FIELD,
|
||||||
|
ElementType.METHOD,
|
||||||
|
ElementType.PACKAGE,
|
||||||
|
ElementType.TYPE,
|
||||||
|
})
|
||||||
|
|
||||||
|
public @interface Strict {
|
||||||
|
String value() default "";
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
|
||||||
|
public @interface SuppressFieldNotInitialized {}
|
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
|
||||||
|
public @interface SuppressFieldNotNullable {}
|
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
|
||||||
|
public @interface SuppressNullFieldAccess {}
|
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
|
||||||
|
public @interface SuppressNullMethodCall {}
|
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
|
||||||
|
public @interface SuppressParameterNotNullable {}
|
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD})
|
||||||
|
public @interface SuppressReturnOverAnnotated {}
|
@ -0,0 +1,19 @@
|
|||||||
|
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
|
|
||||||
|
package com.facebook.infer.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
@Target({
|
||||||
|
ElementType.CONSTRUCTOR,
|
||||||
|
ElementType.METHOD,
|
||||||
|
ElementType.PACKAGE,
|
||||||
|
ElementType.TYPE,
|
||||||
|
})
|
||||||
|
|
||||||
|
public @interface Verify {
|
||||||
|
}
|
@ -0,0 +1,531 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013-present Facebook. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import csv
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import multiprocessing
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import stat
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
# Infer imports
|
||||||
|
import inferlib
|
||||||
|
import utils
|
||||||
|
|
||||||
|
ANALYSIS_SUMMARY_OUTPUT = 'analysis_summary.txt'
|
||||||
|
|
||||||
|
BUCK_CONFIG = '.buckconfig.local'
|
||||||
|
BUCK_CONFIG_BACKUP = '.buckconfig.local.backup_generated_by_BuckAnalyze'
|
||||||
|
DEFAULT_BUCK_OUT = os.path.join(os.getcwd(), 'buck-out')
|
||||||
|
DEFAULT_BUCK_OUT_GEN = os.path.join(DEFAULT_BUCK_OUT, 'gen')
|
||||||
|
|
||||||
|
INFER_REPORT = os.path.join(utils.BUCK_INFER_OUT, utils.CSV_REPORT_FILENAME)
|
||||||
|
INFER_STATS = os.path.join(utils.BUCK_INFER_OUT, utils.STATS_FILENAME)
|
||||||
|
|
||||||
|
INFERJ_SCRIPT = """\
|
||||||
|
#!/bin/sh
|
||||||
|
{0} {1} javac $@
|
||||||
|
"""
|
||||||
|
|
||||||
|
LOCAL_CONFIG = """\
|
||||||
|
[tools]
|
||||||
|
javac = %s
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_build(args):
|
||||||
|
"""Creates script that redirects javac calls to inferJ and a local buck
|
||||||
|
configuration that tells buck to use that script.
|
||||||
|
"""
|
||||||
|
inferJ_options = [
|
||||||
|
'--buck',
|
||||||
|
'--analyzer',
|
||||||
|
args.analyzer,
|
||||||
|
]
|
||||||
|
|
||||||
|
if args.debug:
|
||||||
|
inferJ_options.append('--debug')
|
||||||
|
|
||||||
|
if args.analyzer_mode:
|
||||||
|
inferJ_options.append('--analyzer_mode')
|
||||||
|
inferJ_options.append(args.analyzer_mode)
|
||||||
|
|
||||||
|
# Create a temporary directory as a cache for jar files.
|
||||||
|
infer_cache_dir = os.path.join(args.infer_out, 'cache')
|
||||||
|
if not os.path.isdir(infer_cache_dir):
|
||||||
|
os.mkdir(infer_cache_dir)
|
||||||
|
inferJ_options.append('--infer_cache')
|
||||||
|
inferJ_options.append(infer_cache_dir)
|
||||||
|
temp_files = [infer_cache_dir]
|
||||||
|
|
||||||
|
try:
|
||||||
|
inferJ = utils.get_cmd_in_bin_dir('inferJ') + ' ' +\
|
||||||
|
' '.join(inferJ_options)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
logging.error('Could not find inferJ')
|
||||||
|
raise e
|
||||||
|
|
||||||
|
# Disable the use of buckd as this scripts modifies .buckconfig.local
|
||||||
|
logging.info('Disabling buckd: export NO_BUCKD=1')
|
||||||
|
os.environ['NO_BUCKD'] = '1'
|
||||||
|
|
||||||
|
# make sure INFER_ANALYSIS is set when buck is called
|
||||||
|
logging.info('Setup Infer analysis mode for Buck: export INFER_ANALYSIS=1')
|
||||||
|
os.environ['INFER_ANALYSIS'] = '1'
|
||||||
|
|
||||||
|
# Create a script to be called by buck
|
||||||
|
inferJ_script = None
|
||||||
|
with tempfile.NamedTemporaryFile(delete=False,
|
||||||
|
prefix='inferJ_',
|
||||||
|
suffix='.sh',
|
||||||
|
dir='.') as inferJ_script:
|
||||||
|
logging.info('Creating %s' % inferJ_script.name)
|
||||||
|
inferJ_script.file.write(
|
||||||
|
(INFERJ_SCRIPT.format(sys.executable, inferJ)).encode())
|
||||||
|
|
||||||
|
st = os.stat(inferJ_script.name)
|
||||||
|
os.chmod(inferJ_script.name, st.st_mode | stat.S_IEXEC)
|
||||||
|
|
||||||
|
# Backup and patch local buck config
|
||||||
|
patched_config = ''
|
||||||
|
if os.path.isfile(BUCK_CONFIG):
|
||||||
|
logging.info('Backing up %s to %s', BUCK_CONFIG, BUCK_CONFIG_BACKUP)
|
||||||
|
shutil.move(BUCK_CONFIG, BUCK_CONFIG_BACKUP)
|
||||||
|
with open(BUCK_CONFIG_BACKUP) as buckconfig:
|
||||||
|
patched_config = '\n'.join(buckconfig)
|
||||||
|
|
||||||
|
javac_section = '[tools]\n{0}javac = {1}'.format(
|
||||||
|
' ' * 4,
|
||||||
|
inferJ_script.name)
|
||||||
|
patched_config += javac_section
|
||||||
|
with open(BUCK_CONFIG, 'w') as buckconfig:
|
||||||
|
buckconfig.write(patched_config)
|
||||||
|
|
||||||
|
temp_files += [inferJ_script.name]
|
||||||
|
return temp_files
|
||||||
|
|
||||||
|
|
||||||
|
def java_targets():
|
||||||
|
target_types = [
|
||||||
|
'android_library',
|
||||||
|
'java_library',
|
||||||
|
]
|
||||||
|
try:
|
||||||
|
targets = subprocess.check_output([
|
||||||
|
'buck',
|
||||||
|
'targets',
|
||||||
|
'--type',
|
||||||
|
] + target_types).decode().strip().split('\n')
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
logging.error('Could not compute java library targets')
|
||||||
|
raise e
|
||||||
|
return set(targets)
|
||||||
|
|
||||||
|
|
||||||
|
def is_alias(target):
|
||||||
|
return ':' not in target
|
||||||
|
|
||||||
|
|
||||||
|
def expand_target(target, java_targets):
|
||||||
|
if not is_alias(target):
|
||||||
|
return [target]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
buck_audit_cmd = ['buck', 'audit', 'classpath', '--dot', target]
|
||||||
|
output = subprocess.check_output(buck_audit_cmd)
|
||||||
|
dotty = output.decode().split('\n')
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
logging.error('Could not expand target {0}'.format(target))
|
||||||
|
raise e
|
||||||
|
targets = set()
|
||||||
|
edge_re = re.compile('.*"(.*)".*"(.*)".*')
|
||||||
|
for line in dotty:
|
||||||
|
match = re.match(edge_re, line)
|
||||||
|
if match:
|
||||||
|
for t in match.groups():
|
||||||
|
if t in java_targets:
|
||||||
|
targets.add(t)
|
||||||
|
return targets
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_target(target):
|
||||||
|
if is_alias(target) or target.startswith('//'):
|
||||||
|
return target
|
||||||
|
else:
|
||||||
|
return '//' + target
|
||||||
|
|
||||||
|
|
||||||
|
def determine_library_targets(args):
|
||||||
|
""" Uses git and buck audit to expand aliases into the list of java or
|
||||||
|
android library targets that are parts of these aliases.
|
||||||
|
Buck targets directly passed as argument are not expanded """
|
||||||
|
|
||||||
|
args.targets = [normalize_target(t) for t in args.targets]
|
||||||
|
|
||||||
|
if any(map(is_alias, args.targets)):
|
||||||
|
all_java_targets = java_targets()
|
||||||
|
targets = set()
|
||||||
|
for t in args.targets:
|
||||||
|
targets.update(expand_target(t, all_java_targets))
|
||||||
|
args.targets = list(targets)
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
logging.debug('Targets to analyze:')
|
||||||
|
for target in args.targets:
|
||||||
|
logging.debug(target)
|
||||||
|
|
||||||
|
|
||||||
|
def init_stats(args, start_time):
|
||||||
|
"""Returns dictionary with target independent statistics.
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
'float': {},
|
||||||
|
'int': {
|
||||||
|
'cores': multiprocessing.cpu_count(),
|
||||||
|
'time': int(time.time()),
|
||||||
|
'start_time': int(round(start_time)),
|
||||||
|
},
|
||||||
|
'normal': {
|
||||||
|
'debug': str(args.debug),
|
||||||
|
'analyzer': args.analyzer,
|
||||||
|
'machine': platform.machine(),
|
||||||
|
'node': platform.node(),
|
||||||
|
'project': os.path.basename(os.getcwd()),
|
||||||
|
'revision': utils.vcs_revision(),
|
||||||
|
'branch': utils.vcs_branch(),
|
||||||
|
'system': platform.system(),
|
||||||
|
'infer_version': utils.infer_version(),
|
||||||
|
'infer_branch': utils.infer_branch(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def store_performances_csv(infer_out, stats):
|
||||||
|
"""Stores the statistics about perfromances into a CSV file to be exported
|
||||||
|
to a database"""
|
||||||
|
perf_filename = os.path.join(infer_out, utils.CSV_PERF_FILENAME)
|
||||||
|
with open(perf_filename, 'w') as csv_file_out:
|
||||||
|
csv_writer = csv.writer(csv_file_out)
|
||||||
|
keys = ['infer_version', 'project', 'revision', 'files', 'lines',
|
||||||
|
'cores', 'system', 'machine', 'node', 'total_time',
|
||||||
|
'capture_time', 'analysis_time', 'reporting_time', 'time']
|
||||||
|
int_stats = list(stats['int'].items())
|
||||||
|
normal_stats = list(stats['normal'].items())
|
||||||
|
flat_stats = dict(int_stats + normal_stats)
|
||||||
|
values = []
|
||||||
|
for key in keys:
|
||||||
|
values.append(flat_stats[key])
|
||||||
|
csv_writer.writerow(keys)
|
||||||
|
csv_writer.writerow(values)
|
||||||
|
csv_file_out.flush()
|
||||||
|
|
||||||
|
|
||||||
|
def get_harness_code():
|
||||||
|
all_harness_code = '\nGenerated harness code:\n'
|
||||||
|
for filename in os.listdir(DEFAULT_BUCK_OUT_GEN):
|
||||||
|
if 'InferGeneratedHarness' in filename:
|
||||||
|
all_harness_code += '\n' + filename + ':\n'
|
||||||
|
with open(os.path.join(DEFAULT_BUCK_OUT_GEN,
|
||||||
|
filename), 'r') as file_in:
|
||||||
|
all_harness_code += file_in.read()
|
||||||
|
return all_harness_code + '\n'
|
||||||
|
|
||||||
|
|
||||||
|
def get_basic_stats(stats):
|
||||||
|
files_analyzed = '{0} files ({1} lines) analyzed in {2}s\n\n'.format(
|
||||||
|
stats['int']['files'],
|
||||||
|
stats['int']['lines'],
|
||||||
|
stats['int']['total_time'],
|
||||||
|
)
|
||||||
|
phase_times = 'Capture time: {0}s\nAnalysis time: {1}s\n\n'.format(
|
||||||
|
stats['int']['capture_time'],
|
||||||
|
stats['int']['analysis_time'],
|
||||||
|
)
|
||||||
|
|
||||||
|
to_skip = {
|
||||||
|
'files',
|
||||||
|
'lines',
|
||||||
|
'cores',
|
||||||
|
'time',
|
||||||
|
'start_time',
|
||||||
|
'capture_time',
|
||||||
|
'analysis_time',
|
||||||
|
'reporting_time',
|
||||||
|
'total_time',
|
||||||
|
}
|
||||||
|
bugs_found = 'Errors found:\n\n'
|
||||||
|
for key, value in sorted(stats['int'].items()):
|
||||||
|
if key not in to_skip:
|
||||||
|
bugs_found += ' {0:>8} {1}\n'.format(value, key)
|
||||||
|
|
||||||
|
basic_stats_message = files_analyzed + phase_times + bugs_found + '\n'
|
||||||
|
return basic_stats_message
|
||||||
|
|
||||||
|
|
||||||
|
def get_buck_stats():
|
||||||
|
trace_filename = os.path.join(
|
||||||
|
DEFAULT_BUCK_OUT,
|
||||||
|
'log',
|
||||||
|
'traces',
|
||||||
|
'build.trace'
|
||||||
|
)
|
||||||
|
ARGS = 'args'
|
||||||
|
SUCCESS_STATUS = 'success_type'
|
||||||
|
buck_stats = {}
|
||||||
|
try:
|
||||||
|
with open(trace_filename, 'r') as file_in:
|
||||||
|
trace = json.load(file_in)
|
||||||
|
for t in trace:
|
||||||
|
if SUCCESS_STATUS in t[ARGS]:
|
||||||
|
status = t[ARGS][SUCCESS_STATUS]
|
||||||
|
count = buck_stats.get(status, 0)
|
||||||
|
buck_stats[status] = count + 1
|
||||||
|
|
||||||
|
buck_stats_message = 'Buck build statistics:\n\n'
|
||||||
|
for key, value in sorted(buck_stats.items()):
|
||||||
|
buck_stats_message += ' {0:>8} {1}\n'.format(value, key)
|
||||||
|
|
||||||
|
return buck_stats_message
|
||||||
|
except IOError as e:
|
||||||
|
logging.error('Caught %s: %s' % (e.__class__.__name__, str(e)))
|
||||||
|
logging.error(traceback.format_exc())
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
class NotFoundInJar(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def load_stats(opened_jar):
|
||||||
|
try:
|
||||||
|
return json.loads(opened_jar.read(INFER_STATS).decode())
|
||||||
|
except KeyError as e:
|
||||||
|
raise NotFoundInJar
|
||||||
|
|
||||||
|
|
||||||
|
def load_report(opened_jar):
|
||||||
|
try:
|
||||||
|
sio = io.StringIO(opened_jar.read(INFER_REPORT).decode())
|
||||||
|
return list(csv.reader(sio))
|
||||||
|
except KeyError as e:
|
||||||
|
raise NotFoundInJar
|
||||||
|
|
||||||
|
|
||||||
|
def rows_remove_duplicates(rows):
|
||||||
|
seen = {}
|
||||||
|
result = []
|
||||||
|
for row in rows:
|
||||||
|
t = tuple(row)
|
||||||
|
if t in seen:
|
||||||
|
continue
|
||||||
|
seen[t] = 1
|
||||||
|
result.append(row)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def collect_results(args, start_time):
|
||||||
|
"""Walks through buck-gen, collects results for the different buck targets
|
||||||
|
and stores them in in args.infer_out/results.csv.
|
||||||
|
"""
|
||||||
|
|
||||||
|
buck_stats = get_buck_stats()
|
||||||
|
logging.info(buck_stats)
|
||||||
|
with open(os.path.join(args.infer_out, ANALYSIS_SUMMARY_OUTPUT), 'w') as f:
|
||||||
|
f.write(buck_stats)
|
||||||
|
|
||||||
|
all_rows = []
|
||||||
|
headers = []
|
||||||
|
stats = init_stats(args, start_time)
|
||||||
|
|
||||||
|
accumulation_whitelist = list(map(re.compile, [
|
||||||
|
'^cores$',
|
||||||
|
'^time$',
|
||||||
|
'^start_time$',
|
||||||
|
'.*_pc',
|
||||||
|
]))
|
||||||
|
|
||||||
|
expected_analyzer = stats['normal']['analyzer']
|
||||||
|
expected_version = stats['normal']['infer_version']
|
||||||
|
|
||||||
|
for root, _, files in os.walk(DEFAULT_BUCK_OUT_GEN):
|
||||||
|
for f in [f for f in files if f.endswith('.jar')]:
|
||||||
|
path = os.path.join(root, f)
|
||||||
|
try:
|
||||||
|
with zipfile.ZipFile(path) as jar:
|
||||||
|
# Accumulate integers and float values
|
||||||
|
target_stats = load_stats(jar)
|
||||||
|
|
||||||
|
found_analyzer = target_stats['normal']['analyzer']
|
||||||
|
found_version = target_stats['normal']['infer_version']
|
||||||
|
|
||||||
|
if (found_analyzer != expected_analyzer
|
||||||
|
or found_version != expected_version):
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
for type_k in ['int', 'float']:
|
||||||
|
items = target_stats.get(type_k, {}).items()
|
||||||
|
for key, value in items:
|
||||||
|
if not any(map(lambda r: r.match(key),
|
||||||
|
accumulation_whitelist)):
|
||||||
|
old_value = stats[type_k].get(key, 0)
|
||||||
|
stats[type_k][key] = old_value + value
|
||||||
|
|
||||||
|
rows = load_report(jar)
|
||||||
|
if len(rows) > 0:
|
||||||
|
headers.append(rows[0])
|
||||||
|
all_rows.extend(rows[1:])
|
||||||
|
|
||||||
|
# Override normals
|
||||||
|
stats['normal'].update(target_stats.get('normal', {}))
|
||||||
|
except NotFoundInJar:
|
||||||
|
pass
|
||||||
|
except zipfile.BadZipfile:
|
||||||
|
logging.warn('Bad zip file %s', path)
|
||||||
|
|
||||||
|
csv_report = os.path.join(args.infer_out, utils.CSV_REPORT_FILENAME)
|
||||||
|
bugs_out = os.path.join(args.infer_out, utils.BUGS_FILENAME)
|
||||||
|
|
||||||
|
if len(headers) == 0:
|
||||||
|
with open(csv_report, 'w'):
|
||||||
|
pass
|
||||||
|
logging.info('No reports found')
|
||||||
|
return
|
||||||
|
elif len(headers) > 1:
|
||||||
|
if any(map(lambda x: x != headers[0], headers)):
|
||||||
|
raise Exception('Inconsistent reports found')
|
||||||
|
|
||||||
|
# Convert all float values to integer values
|
||||||
|
for key, value in stats.get('float', {}).items():
|
||||||
|
stats['int'][key] = int(round(value))
|
||||||
|
|
||||||
|
# Delete the float entries before exporting the results
|
||||||
|
del(stats['float'])
|
||||||
|
|
||||||
|
with open(csv_report, 'w') as report:
|
||||||
|
writer = csv.writer(report)
|
||||||
|
writer.writerows([headers[0]] + rows_remove_duplicates(all_rows))
|
||||||
|
report.flush()
|
||||||
|
|
||||||
|
# export the CSV rows to JSON
|
||||||
|
utils.create_json_report(args.infer_out)
|
||||||
|
|
||||||
|
print('\n')
|
||||||
|
inferlib.print_errors(csv_report, bugs_out, args.analyzer)
|
||||||
|
|
||||||
|
stats['int']['total_time'] = int(round(utils.elapsed_time(start_time)))
|
||||||
|
|
||||||
|
store_performances_csv(args.infer_out, stats)
|
||||||
|
|
||||||
|
stats_filename = os.path.join(args.infer_out, utils.STATS_FILENAME)
|
||||||
|
with open(stats_filename, 'w') as stats_out:
|
||||||
|
json.dump(stats, stats_out)
|
||||||
|
|
||||||
|
basic_stats = get_basic_stats(stats)
|
||||||
|
|
||||||
|
if args.print_harness:
|
||||||
|
harness_code = get_harness_code()
|
||||||
|
basic_stats += harness_code
|
||||||
|
|
||||||
|
logging.info(basic_stats)
|
||||||
|
|
||||||
|
with open(os.path.join(args.infer_out, ANALYSIS_SUMMARY_OUTPUT), 'a') as f:
|
||||||
|
f.write(basic_stats)
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup(temp_files):
|
||||||
|
"""Removes the generated .buckconfig.local and the temporary inferJ script.
|
||||||
|
"""
|
||||||
|
for file in [BUCK_CONFIG] + temp_files:
|
||||||
|
try:
|
||||||
|
logging.info('Removing %s' % file)
|
||||||
|
if os.path.isdir(file):
|
||||||
|
shutil.rmtree(file)
|
||||||
|
else:
|
||||||
|
os.unlink(file)
|
||||||
|
except IOError:
|
||||||
|
logging.error('Could not remove %s' % file)
|
||||||
|
|
||||||
|
if os.path.isfile(BUCK_CONFIG_BACKUP):
|
||||||
|
logging.info('Restoring %s', BUCK_CONFIG)
|
||||||
|
shutil.move(BUCK_CONFIG_BACKUP, BUCK_CONFIG)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(parents=[inferlib.base_parser])
|
||||||
|
parser.add_argument('--verbose', action='store_true',
|
||||||
|
help='Print buck compilation steps')
|
||||||
|
parser.add_argument('--no-cache', action='store_true',
|
||||||
|
help='Do not use buck distributed cache')
|
||||||
|
parser.add_argument('--print-harness', action='store_true',
|
||||||
|
help='Print generated harness code (Android only)')
|
||||||
|
parser.add_argument('targets', nargs='*', metavar='target',
|
||||||
|
help='Build targets to analyze')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
utils.configure_logging(args.verbose)
|
||||||
|
timer = utils.Timer(logging.info)
|
||||||
|
temp_files = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
start_time = time.time()
|
||||||
|
logging.info('Starting the analysis')
|
||||||
|
subprocess.check_call(
|
||||||
|
[utils.get_cmd_in_bin_dir('InferAnalyze'), '-version'])
|
||||||
|
|
||||||
|
if not os.path.isdir(args.infer_out):
|
||||||
|
os.mkdir(args.infer_out)
|
||||||
|
|
||||||
|
timer.start('Preparing build...')
|
||||||
|
temp_files += prepare_build(args)
|
||||||
|
timer.stop('Build prepared')
|
||||||
|
|
||||||
|
# TODO(t3786463) Start buckd.
|
||||||
|
|
||||||
|
timer.start('Computing library targets')
|
||||||
|
determine_library_targets(args)
|
||||||
|
timer.stop('%d targets computed', len(args.targets))
|
||||||
|
|
||||||
|
timer.start('Running buck...')
|
||||||
|
buck_cmd = ['buck', 'build']
|
||||||
|
if args.no_cache:
|
||||||
|
buck_cmd += ['--no-cache']
|
||||||
|
if args.verbose:
|
||||||
|
buck_cmd += ['-v', '2']
|
||||||
|
subprocess.check_call(buck_cmd + args.targets)
|
||||||
|
timer.stop('Buck finished')
|
||||||
|
|
||||||
|
timer.start('Collecting results...')
|
||||||
|
collect_results(args, start_time)
|
||||||
|
timer.stop('Done')
|
||||||
|
|
||||||
|
except KeyboardInterrupt as e:
|
||||||
|
timer.stop('Exiting')
|
||||||
|
sys.exit(0)
|
||||||
|
except Exception as e:
|
||||||
|
timer.stop('Failed')
|
||||||
|
logging.error('Caught %s: %s' % (e.__class__.__name__, str(e)))
|
||||||
|
logging.error(traceback.format_exc())
|
||||||
|
sys.exit(1)
|
||||||
|
finally:
|
||||||
|
cleanup(temp_files)
|
||||||
|
|
||||||
|
|
||||||
|
# vim: set sw=4 ts=4 et:
|
@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import imp
|
||||||
|
import inferlib
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
SCRIPT_FOLDER = os.path.dirname(__file__)
|
||||||
|
CAPTURE_PACKAGE = 'capture'
|
||||||
|
LIB_FOLDER = os.path.join(
|
||||||
|
os.path.dirname(__file__), os.path.pardir, 'lib')
|
||||||
|
|
||||||
|
# token that identifies the end of the options for infer and the beginning
|
||||||
|
# of the compilation command
|
||||||
|
CMD_MARKER = '--'
|
||||||
|
|
||||||
|
# insert here the correspondence between module name and the list of
|
||||||
|
# compiler/build-systems it handles.
|
||||||
|
# All supported commands should be listed here
|
||||||
|
MODULE_TO_COMMAND = {
|
||||||
|
'ant': ['ant'],
|
||||||
|
'analyze': ['analyze'],
|
||||||
|
'buck': ['buck'],
|
||||||
|
'gradle': ['gradle', 'gradlew'],
|
||||||
|
'javac': ['javac'],
|
||||||
|
'make': ['make', 'clang', 'clang++', 'cc', 'gcc', 'g++'],
|
||||||
|
'xcodebuild': ['xcodebuild'],
|
||||||
|
'mvn': ['mvn']
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_commands():
|
||||||
|
"""Return all commands that are supported."""
|
||||||
|
#flatten and dedup the list of commands
|
||||||
|
return set(sum(MODULE_TO_COMMAND.values(), []))
|
||||||
|
|
||||||
|
|
||||||
|
def get_module_name(command):
|
||||||
|
""" Return module that is able to handle the command. None if
|
||||||
|
there is no such module."""
|
||||||
|
for module, commands in MODULE_TO_COMMAND.iteritems():
|
||||||
|
if command in commands:
|
||||||
|
return module
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def load_module(mod_name):
|
||||||
|
# load the 'capture' package in lib
|
||||||
|
pkg_info = imp.find_module(CAPTURE_PACKAGE, [LIB_FOLDER])
|
||||||
|
imported_pkg = imp.load_module(CAPTURE_PACKAGE, *pkg_info)
|
||||||
|
# load the requested module (e.g. make)
|
||||||
|
mod_file, mod_path, mod_descr = \
|
||||||
|
imp.find_module(mod_name, imported_pkg.__path__)
|
||||||
|
try:
|
||||||
|
return imp.load_module(
|
||||||
|
'{pkg}.{mod}'.format(pkg=imported_pkg.__name__, mod=mod_name),
|
||||||
|
mod_file, mod_path, mod_descr)
|
||||||
|
finally:
|
||||||
|
if mod_file:
|
||||||
|
mod_file.close()
|
||||||
|
|
||||||
|
|
||||||
|
def split_args_to_parse():
|
||||||
|
dd_index = \
|
||||||
|
sys.argv.index(CMD_MARKER) if CMD_MARKER in sys.argv else len(sys.argv)
|
||||||
|
return sys.argv[1:dd_index], sys.argv[dd_index + 1:]
|
||||||
|
|
||||||
|
|
||||||
|
def create_argparser(parents=[]):
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
parents=[inferlib.inferJ_parser] + parents,
|
||||||
|
add_help=False,
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
)
|
||||||
|
group = parser.add_argument_group(
|
||||||
|
'supported compiler/build-system commands')
|
||||||
|
|
||||||
|
supported_commands = ', '.join(get_commands())
|
||||||
|
group.add_argument(
|
||||||
|
CMD_MARKER,
|
||||||
|
metavar='<cmd>',
|
||||||
|
dest='nullarg',
|
||||||
|
default=None,
|
||||||
|
help=('Command to run the compiler/build-system. '
|
||||||
|
'Supported build commands (run `infer --help -- <cmd_name>` for '
|
||||||
|
'extra help, e.g. `infer --help -- javac`): ' + supported_commands),
|
||||||
|
)
|
||||||
|
return parser
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
to_parse, cmd = split_args_to_parse()
|
||||||
|
# get the module name (if any), then load it
|
||||||
|
capture_module_name = os.path.basename(cmd[0]) if len(cmd) > 0 else None
|
||||||
|
mod_name = get_module_name(capture_module_name)
|
||||||
|
imported_module = None
|
||||||
|
if mod_name:
|
||||||
|
# There is module that supports the command
|
||||||
|
imported_module = load_module(mod_name)
|
||||||
|
|
||||||
|
# get the module's argparser and merge it with the global argparser
|
||||||
|
module_argparser = []
|
||||||
|
if imported_module:
|
||||||
|
module_argparser.append(
|
||||||
|
imported_module.create_argparser(capture_module_name)
|
||||||
|
)
|
||||||
|
global_argparser = create_argparser(module_argparser)
|
||||||
|
|
||||||
|
args = global_argparser.parse_args(to_parse)
|
||||||
|
|
||||||
|
if imported_module:
|
||||||
|
if capture_module_name != 'analyze' and not args.incremental:
|
||||||
|
inferlib.remove_infer_out(args.infer_out)
|
||||||
|
capture_exitcode = imported_module.gen_instance(args, cmd).capture()
|
||||||
|
if capture_exitcode != os.EX_OK:
|
||||||
|
exit(capture_exitcode)
|
||||||
|
elif capture_module_name is not None:
|
||||||
|
# There was a command, but it's not supported
|
||||||
|
print('Command "{cmd}" not recognised'.format(
|
||||||
|
cmd='' if capture_module_name is None else capture_module_name))
|
||||||
|
global_argparser.print_help()
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
global_argparser.print_help()
|
||||||
|
sys.exit(os.EX_OK)
|
||||||
|
|
||||||
|
if not (mod_name == 'buck' or mod_name == 'javac'):
|
||||||
|
# Something should be already captured, otherwise analysis would fail
|
||||||
|
if not os.path.exists(os.path.join(args.infer_out, 'captured')):
|
||||||
|
print('There was nothing to analyze, exiting')
|
||||||
|
exit(os.EX_USAGE)
|
||||||
|
analysis = inferlib.Infer(args, [])
|
||||||
|
analysis.analyze_and_report()
|
||||||
|
analysis.save_stats()
|
||||||
|
|
||||||
|
main()
|
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# Copyright (c) 2013- Facebook. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import inferlib
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
cmd_args = sys.argv[1:]
|
||||||
|
analysis = inferlib.Infer(inferlib.get_inferJ_args(cmd_args),
|
||||||
|
inferlib.get_javac_args(cmd_args))
|
||||||
|
stats = analysis.start()
|
||||||
|
|
||||||
|
if stats:
|
||||||
|
logging.info('Capture time: {0:.2f}s'.format(
|
||||||
|
stats['float']['capture_time']
|
||||||
|
))
|
||||||
|
logging.info('Analysis time: {0:.2f}s'.format(
|
||||||
|
stats['float']['analysis_time']
|
||||||
|
))
|
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash -e
|
||||||
|
|
||||||
|
# Copyright (c) 2013 - Facebook.
|
||||||
|
# All rights reserved.
|
||||||
|
|
||||||
|
# This script takes a buck target and runs the respective tests.
|
||||||
|
|
||||||
|
# Arguments:
|
||||||
|
# $1 : buck target
|
||||||
|
# [$2] : "keep" or "replace". Keep will keep the temporary folders used in the tests.
|
||||||
|
# Replace will replace the saved dot files with the new created ones.
|
||||||
|
|
||||||
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
cd $SCRIPT_DIR/../../
|
||||||
|
|
||||||
|
case $2 in
|
||||||
|
keep)
|
||||||
|
INFER_KEEP_FOLDER=Y buck test --no-results-cache $1 ;;
|
||||||
|
replace)
|
||||||
|
INFER_DOT_REPLACE=Y buck test --no-results-cache $1 ;;
|
||||||
|
*)
|
||||||
|
buck test --no-results-cache $1 ;;
|
||||||
|
esac
|
@ -0,0 +1,648 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2013- Facebook. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import csv
|
||||||
|
import glob
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import multiprocessing
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
# Increase the limit of the CSV parser to sys.maxlimit
|
||||||
|
csv.field_size_limit(sys.maxsize)
|
||||||
|
|
||||||
|
# Infer imports
|
||||||
|
import jwlib
|
||||||
|
import utils
|
||||||
|
|
||||||
|
# list of analysis options
|
||||||
|
INFER = 'infer'
|
||||||
|
ERADICATE = 'eradicate'
|
||||||
|
CHECKERS = 'checkers'
|
||||||
|
CAPTURE = 'capture'
|
||||||
|
COMPILE = 'compile'
|
||||||
|
TRACING = 'tracing'
|
||||||
|
|
||||||
|
MODES = [COMPILE, CAPTURE, INFER, ERADICATE, CHECKERS, TRACING]
|
||||||
|
|
||||||
|
INFER_ANALYZE_BINARY = "InferAnalyze"
|
||||||
|
|
||||||
|
class AbsolutePathAction(argparse.Action):
|
||||||
|
"""Convert a path from relative to absolute in the arg parser"""
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
setattr(namespace, self.dest, os.path.abspath(values))
|
||||||
|
|
||||||
|
|
||||||
|
# https://github.com/python/cpython/blob/aa8ea3a6be22c92e774df90c6a6ee697915ca8ec/Lib/argparse.py
|
||||||
|
class VersionAction(argparse._VersionAction):
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
# set self.version so that argparse version action knows it
|
||||||
|
self.version = self.get_infer_version()
|
||||||
|
super(VersionAction, self).__call__(parser,
|
||||||
|
namespace,
|
||||||
|
values,
|
||||||
|
option_string)
|
||||||
|
|
||||||
|
def get_infer_version(self):
|
||||||
|
try:
|
||||||
|
return subprocess.check_output([
|
||||||
|
utils.get_cmd_in_bin_dir(INFER_ANALYZE_BINARY), '-version'])
|
||||||
|
except:
|
||||||
|
print("Failed to run {0} binary, exiting".
|
||||||
|
format(INFER_ANALYZE_BINARY))
|
||||||
|
exit(2)
|
||||||
|
|
||||||
|
|
||||||
|
base_parser = argparse.ArgumentParser(add_help=False)
|
||||||
|
base_group = base_parser.add_argument_group('global arguments')
|
||||||
|
base_group.add_argument('-o', '--out', metavar='<directory>',
|
||||||
|
default=utils.DEFAULT_INFER_OUT, dest='infer_out',
|
||||||
|
action=AbsolutePathAction,
|
||||||
|
help='Set the INFER results directory')
|
||||||
|
base_group.add_argument('-i', '--incremental', action='store_true',
|
||||||
|
help='''Do not delete the results directory across
|
||||||
|
Infer runs''')
|
||||||
|
base_group.add_argument('-g', '--debug', action='store_true',
|
||||||
|
help='Generate extra debugging information')
|
||||||
|
base_group.add_argument('-a', '--analyzer',
|
||||||
|
help='Select the analyzer within: {0}'.format(
|
||||||
|
', '.join(MODES)),
|
||||||
|
default=INFER)
|
||||||
|
base_group.add_argument('-m', '--analyzer_mode', metavar='<analyzer_mode>',
|
||||||
|
help='''Select a special analyzer mode such as
|
||||||
|
graphql1 or graphql2''')
|
||||||
|
base_parser.add_argument('-v', '--version', help='Get version of the analyzer',
|
||||||
|
action=VersionAction)
|
||||||
|
|
||||||
|
|
||||||
|
inferJ_parser = argparse.ArgumentParser(parents=[base_parser])
|
||||||
|
inferJ_group = inferJ_parser.add_argument_group('backend arguments')
|
||||||
|
inferJ_group.add_argument('-j', '--multicore', metavar='n', type=int,
|
||||||
|
default=multiprocessing.cpu_count(),
|
||||||
|
dest='multicore', help='Set the number of cores to '
|
||||||
|
'be used for the analysis (default uses all cores)')
|
||||||
|
inferJ_group.add_argument('-x', '--project', metavar='<projectname>',
|
||||||
|
help='Project name, for recording purposes only')
|
||||||
|
|
||||||
|
inferJ_group.add_argument('-r', '--revision', metavar='<githash>',
|
||||||
|
help='The githash, for recording purposes only')
|
||||||
|
|
||||||
|
inferJ_group.add_argument('--buck', action='store_true', dest='buck',
|
||||||
|
help='To use when run with buck')
|
||||||
|
|
||||||
|
inferJ_group.add_argument('--infer_cache', metavar='<directory>',
|
||||||
|
help='Select a directory to contain the infer cache')
|
||||||
|
|
||||||
|
inferJ_group.add_argument('-pr', '--project_root',
|
||||||
|
dest='project_root',
|
||||||
|
default=os.getcwd(),
|
||||||
|
help='Location of the project root '
|
||||||
|
'(default is current directory)')
|
||||||
|
|
||||||
|
inferJ_group.add_argument('--objc_ml_buckets',
|
||||||
|
dest='objc_ml_buckets',
|
||||||
|
help='memory leak buckets to be checked, '
|
||||||
|
'separated by commas. The possible '
|
||||||
|
'buckets are cf (Core Foundation), '
|
||||||
|
'arc, narc (No arc)')
|
||||||
|
|
||||||
|
inferJ_group.add_argument('-nt', '--notest', action='store_true',
|
||||||
|
dest='notest',
|
||||||
|
help='Prints output of symbolic execution')
|
||||||
|
|
||||||
|
def detect_javac(args):
|
||||||
|
for index, arg in enumerate(args):
|
||||||
|
if arg == 'javac':
|
||||||
|
return index
|
||||||
|
|
||||||
|
|
||||||
|
def get_inferJ_args(args):
|
||||||
|
index = detect_javac(args)
|
||||||
|
if index is None:
|
||||||
|
cmd_args = args
|
||||||
|
else:
|
||||||
|
cmd_args = args[:index]
|
||||||
|
return inferJ_parser.parse_args(cmd_args)
|
||||||
|
|
||||||
|
|
||||||
|
def get_javac_args(args):
|
||||||
|
javac_args = args[detect_javac(args) + 1:]
|
||||||
|
if len(javac_args) == 0:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
# replace any -g:.* flag with -g to preserve debugging symbols
|
||||||
|
return map(lambda arg: '-g' if '-g:' in arg else arg, javac_args)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_infer_out(infer_out):
|
||||||
|
# it is safe to ignore errors here because recreating the infer_out
|
||||||
|
# directory will fail later
|
||||||
|
shutil.rmtree(infer_out, True)
|
||||||
|
|
||||||
|
|
||||||
|
def clean_infer_out(infer_out):
|
||||||
|
|
||||||
|
directories = ['multicore', 'classnames', 'sources']
|
||||||
|
extensions = ['.cfg', '.cg']
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(infer_out):
|
||||||
|
for d in dirs:
|
||||||
|
if d in directories:
|
||||||
|
path = os.path.join(root, d)
|
||||||
|
shutil.rmtree(path)
|
||||||
|
for f in files:
|
||||||
|
for ext in extensions:
|
||||||
|
if f.endswith(ext):
|
||||||
|
path = os.path.join(root, f)
|
||||||
|
os.remove(path)
|
||||||
|
|
||||||
|
|
||||||
|
def help_exit(message):
|
||||||
|
print(message)
|
||||||
|
inferJ_parser.print_usage()
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def compare_rows(row_1, row_2):
|
||||||
|
filename_1 = row_1[utils.CSV_INDEX_FILENAME]
|
||||||
|
filename_2 = row_2[utils.CSV_INDEX_FILENAME]
|
||||||
|
if filename_1 < filename_2:
|
||||||
|
return -1
|
||||||
|
elif filename_1 > filename_2:
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
line_1 = int(row_1[utils.CSV_INDEX_LINE])
|
||||||
|
line_2 = int(row_2[utils.CSV_INDEX_LINE])
|
||||||
|
return line_1 - line_2
|
||||||
|
|
||||||
|
|
||||||
|
def sort_csv(csv_report, infer_out):
|
||||||
|
collected_rows = []
|
||||||
|
with open(csv_report, 'r') as file_in:
|
||||||
|
reader = csv.reader(file_in)
|
||||||
|
rows = [row for row in reader]
|
||||||
|
if len(rows) <= 1:
|
||||||
|
return rows
|
||||||
|
else:
|
||||||
|
for row in rows[1:]:
|
||||||
|
filename = row[utils.CSV_INDEX_FILENAME]
|
||||||
|
if os.path.isfile(filename):
|
||||||
|
collected_rows.append(row)
|
||||||
|
collected_rows = sorted(
|
||||||
|
collected_rows,
|
||||||
|
cmp=compare_rows)
|
||||||
|
collected_rows = [rows[0]] + collected_rows
|
||||||
|
temporary_file = tempfile.mktemp()
|
||||||
|
with open(temporary_file, 'w') as file_out:
|
||||||
|
writer = csv.writer(file_out)
|
||||||
|
writer.writerows(collected_rows)
|
||||||
|
file_out.flush()
|
||||||
|
shutil.move(temporary_file, csv_report)
|
||||||
|
|
||||||
|
|
||||||
|
def should_print(analyzer, row):
|
||||||
|
error_kind = row[utils.CSV_INDEX_KIND]
|
||||||
|
error_type = row[utils.CSV_INDEX_TYPE]
|
||||||
|
error_bucket = '' # can be updated later once we extract it from qualifier
|
||||||
|
|
||||||
|
try:
|
||||||
|
qualifier_xml = ET.fromstring(row[utils.CSV_INDEX_QUALIFIER_TAGS])
|
||||||
|
if qualifier_xml.tag == utils.QUALIFIER_TAGS:
|
||||||
|
bucket = qualifier_xml.find(utils.BUCKET_TAGS)
|
||||||
|
if bucket is not None:
|
||||||
|
error_bucket = bucket.text
|
||||||
|
except ET.ParseError:
|
||||||
|
pass # this will skip any invalid xmls
|
||||||
|
|
||||||
|
# config what to print is listed below
|
||||||
|
error_kinds = ['ERROR', 'WARNING']
|
||||||
|
|
||||||
|
null_style_bugs = [
|
||||||
|
'NULL_DEREFERENCE',
|
||||||
|
'PARAMETER_NOT_NULL_CHECKED',
|
||||||
|
'IVAR_NOT_NULL_CHECKED',
|
||||||
|
'PREMATURE_NIL_TERMINATION_ARGUMENT',
|
||||||
|
]
|
||||||
|
null_style_buckets = ['B1', 'B2']
|
||||||
|
|
||||||
|
other_bugs = ['RESOURCE_LEAK', 'MEMORY_LEAK', 'RETAIN_CYCLE']
|
||||||
|
|
||||||
|
filter_by_type = True
|
||||||
|
if analyzer in [ERADICATE, CHECKERS]:
|
||||||
|
# report all issues for eredicate and checkers
|
||||||
|
filter_by_type = False
|
||||||
|
|
||||||
|
if error_kind not in error_kinds:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not filter_by_type:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not error_type:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if error_type in null_style_bugs:
|
||||||
|
if error_bucket and error_bucket in null_style_buckets:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
elif error_type in other_bugs:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def remove_bucket(bug_message):
|
||||||
|
""" Remove anything from the beginning if the message that
|
||||||
|
looks like a bucket """
|
||||||
|
return re.sub(r'(^\[[a-zA-Z0-9]*\])', '', bug_message, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def print_and_write(file_out, message):
|
||||||
|
print(message)
|
||||||
|
file_out.write(message + '\n')
|
||||||
|
|
||||||
|
|
||||||
|
def print_errors(csv_report, bugs_out, analyzer):
|
||||||
|
with open(csv_report, 'r') as file_in:
|
||||||
|
reader = csv.reader(file_in)
|
||||||
|
reader.next() # first line is header, skip it
|
||||||
|
|
||||||
|
errors = filter(
|
||||||
|
lambda row: should_print(analyzer, row),
|
||||||
|
reader
|
||||||
|
)
|
||||||
|
with open(bugs_out, 'w') as file_out:
|
||||||
|
if not errors:
|
||||||
|
print_and_write(file_out, 'No issues found')
|
||||||
|
for row in errors:
|
||||||
|
filename = row[utils.CSV_INDEX_FILENAME]
|
||||||
|
if os.path.isfile(filename):
|
||||||
|
kind = row[utils.CSV_INDEX_KIND]
|
||||||
|
line = row[utils.CSV_INDEX_LINE]
|
||||||
|
error_type = row[utils.CSV_INDEX_TYPE]
|
||||||
|
msg = remove_bucket(row[utils.CSV_INDEX_QUALIFIER])
|
||||||
|
print_and_write(
|
||||||
|
file_out,
|
||||||
|
'{0}:{1}: {2}: {3}\n {4}\n'.format(
|
||||||
|
filename,
|
||||||
|
line,
|
||||||
|
kind.lower(),
|
||||||
|
error_type,
|
||||||
|
msg,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(cmd, debug_mode, javac_arguments, step, analyzer):
|
||||||
|
if debug_mode:
|
||||||
|
print('\n{0}\n'.format(' '.join(cmd)))
|
||||||
|
try:
|
||||||
|
return subprocess.check_call(cmd)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
error_msg = 'Failure during {0}, original command was\n\n{1}\n\n'
|
||||||
|
inferJ_cmd = ['inferJ', '-g', '-a', analyzer]
|
||||||
|
failing_cmd = inferJ_cmd + ['javac'] + javac_arguments
|
||||||
|
logging.error(error_msg.format(
|
||||||
|
step,
|
||||||
|
failing_cmd
|
||||||
|
))
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
class Infer:
|
||||||
|
|
||||||
|
def __init__(self, args, javac_args):
|
||||||
|
|
||||||
|
self.args = args
|
||||||
|
if self.args.analyzer not in MODES:
|
||||||
|
help_exit(
|
||||||
|
'Unknown analysis mode \"{0}\"'.format(self.args.analyzer)
|
||||||
|
)
|
||||||
|
|
||||||
|
utils.configure_logging(self.args.debug)
|
||||||
|
|
||||||
|
self.javac = jwlib.CompilerCall(javac_args)
|
||||||
|
|
||||||
|
if not self.javac.args.version:
|
||||||
|
if javac_args is None:
|
||||||
|
help_exit('No javac command detected')
|
||||||
|
|
||||||
|
if self.args.infer_out is None:
|
||||||
|
help_exit('Expect INFER results directory')
|
||||||
|
|
||||||
|
if self.args.buck:
|
||||||
|
self.args.infer_out = os.path.join(
|
||||||
|
self.javac.args.classes_out,
|
||||||
|
utils.BUCK_INFER_OUT)
|
||||||
|
self.args.infer_out = os.path.abspath(self.args.infer_out)
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.mkdir(self.args.infer_out)
|
||||||
|
except OSError as e:
|
||||||
|
if not os.path.isdir(self.args.infer_out):
|
||||||
|
raise e
|
||||||
|
|
||||||
|
self.stats = {'int': {}, 'float': {}}
|
||||||
|
self.timing = {}
|
||||||
|
|
||||||
|
def clean_exit(self):
|
||||||
|
if os.path.isdir(self.args.infer_out):
|
||||||
|
print('removing', self.args.infer_out)
|
||||||
|
shutil.rmtree(self.args.infer_out)
|
||||||
|
exit(os.EX_OK)
|
||||||
|
|
||||||
|
def run_infer_frontend(self):
|
||||||
|
|
||||||
|
infer_cmd = [utils.get_cmd_in_bin_dir('InferJava')]
|
||||||
|
|
||||||
|
if self.args.buck:
|
||||||
|
infer_cmd += ['-project_root', os.getcwd()]
|
||||||
|
|
||||||
|
infer_cmd += [
|
||||||
|
'-results_dir', self.args.infer_out,
|
||||||
|
'-verbose_out', self.javac.verbose_out,
|
||||||
|
]
|
||||||
|
|
||||||
|
if os.path.isfile(utils.MODELS_JAR):
|
||||||
|
infer_cmd += ['-models', utils.MODELS_JAR]
|
||||||
|
|
||||||
|
infer_cmd.append('-no-static_final')
|
||||||
|
|
||||||
|
if self.args.debug:
|
||||||
|
infer_cmd.append('-debug')
|
||||||
|
if self.args.analyzer == TRACING:
|
||||||
|
infer_cmd.append('-tracing')
|
||||||
|
|
||||||
|
return run_command(
|
||||||
|
infer_cmd,
|
||||||
|
self.args.debug,
|
||||||
|
self.javac.original_arguments,
|
||||||
|
'frontend',
|
||||||
|
self.args.analyzer
|
||||||
|
)
|
||||||
|
|
||||||
|
def compile(self):
|
||||||
|
return self.javac.run()
|
||||||
|
|
||||||
|
def capture(self):
|
||||||
|
javac_status = self.compile()
|
||||||
|
if javac_status == os.EX_OK:
|
||||||
|
return self.run_infer_frontend()
|
||||||
|
else:
|
||||||
|
return javac_status
|
||||||
|
|
||||||
|
def analyze(self):
|
||||||
|
infer_analyze = [
|
||||||
|
utils.get_cmd_in_bin_dir(INFER_ANALYZE_BINARY),
|
||||||
|
'-results_dir',
|
||||||
|
self.args.infer_out
|
||||||
|
]
|
||||||
|
infer_options = []
|
||||||
|
|
||||||
|
# remove specs if possible so that old issues are less likely
|
||||||
|
# to be reported
|
||||||
|
infer_options += ['-allow_specs_cleanup']
|
||||||
|
|
||||||
|
if self.args.analyzer == ERADICATE:
|
||||||
|
infer_options += ['-checkers', '-eradicate']
|
||||||
|
elif self.args.analyzer == CHECKERS:
|
||||||
|
infer_options += ['-checkers']
|
||||||
|
else:
|
||||||
|
if self.args.analyzer == TRACING:
|
||||||
|
infer_options.append('-tracing')
|
||||||
|
if os.path.isfile(utils.MODELS_JAR):
|
||||||
|
infer_options += ['-models', utils.MODELS_JAR]
|
||||||
|
|
||||||
|
if self.args.analyzer_mode:
|
||||||
|
infer_options += ['-analyzer_mode', self.args.analyzer_mode]
|
||||||
|
|
||||||
|
if self.args.infer_cache:
|
||||||
|
infer_options += ['-infer_cache', self.args.infer_cache]
|
||||||
|
|
||||||
|
if self.args.objc_ml_buckets:
|
||||||
|
infer_options += ['-objc_ml_buckets', self.args.objc_ml_buckets]
|
||||||
|
|
||||||
|
if self.args.notest:
|
||||||
|
infer_options += ['-notest']
|
||||||
|
|
||||||
|
if self.args.debug:
|
||||||
|
infer_options += [
|
||||||
|
'-developer_mode',
|
||||||
|
'-html',
|
||||||
|
'-dotty',
|
||||||
|
'-print_types',
|
||||||
|
'-trace_error',
|
||||||
|
# '-notest',
|
||||||
|
]
|
||||||
|
|
||||||
|
exit_status = os.EX_OK
|
||||||
|
|
||||||
|
if self.args.buck:
|
||||||
|
infer_options += ['-project_root', os.getcwd(), '-java']
|
||||||
|
if self.javac.args.classpath is not None:
|
||||||
|
for path in self.javac.args.classpath.split(os.pathsep):
|
||||||
|
if os.path.isfile(path):
|
||||||
|
infer_options += ['-ziplib', os.path.abspath(path)]
|
||||||
|
elif self.args.project_root:
|
||||||
|
infer_options += ['-project_root', self.args.project_root]
|
||||||
|
|
||||||
|
if self.args.multicore == 1:
|
||||||
|
analyze_cmd = infer_analyze + infer_options
|
||||||
|
exit_status = run_command(
|
||||||
|
analyze_cmd,
|
||||||
|
self.args.debug,
|
||||||
|
self.javac.original_arguments,
|
||||||
|
'analysis',
|
||||||
|
self.args.analyzer
|
||||||
|
)
|
||||||
|
|
||||||
|
else:
|
||||||
|
if self.args.analyzer in [ERADICATE, CHECKERS]:
|
||||||
|
infer_analyze.append('-intraprocedural')
|
||||||
|
|
||||||
|
os.environ['INFER_OPTIONS'] = ' '.join(infer_options)
|
||||||
|
|
||||||
|
multicore_dir = os.path.join(self.args.infer_out, 'multicore')
|
||||||
|
pwd = os.getcwd()
|
||||||
|
if os.path.isdir(multicore_dir):
|
||||||
|
shutil.rmtree(multicore_dir)
|
||||||
|
os.mkdir(multicore_dir)
|
||||||
|
os.chdir(multicore_dir)
|
||||||
|
os.environ['INFER_DEVELOPER'] = 'Y'
|
||||||
|
analyze_cmd = infer_analyze + ['-makefile', 'Makefile']
|
||||||
|
analyze_cmd += infer_options
|
||||||
|
makefile_status = run_command(
|
||||||
|
analyze_cmd,
|
||||||
|
self.args.debug,
|
||||||
|
self.javac.original_arguments,
|
||||||
|
'create_makefile',
|
||||||
|
self.args.analyzer
|
||||||
|
)
|
||||||
|
exit_status += makefile_status
|
||||||
|
if makefile_status == os.EX_OK:
|
||||||
|
make_cmd = ['make', '-k', '-j', str(self.args.multicore)]
|
||||||
|
if not self.args.debug:
|
||||||
|
make_cmd += ['-s']
|
||||||
|
make_status = run_command(
|
||||||
|
make_cmd,
|
||||||
|
self.args.debug,
|
||||||
|
self.javac.original_arguments,
|
||||||
|
'run_makefile',
|
||||||
|
self.args.analyzer
|
||||||
|
)
|
||||||
|
os.chdir(pwd)
|
||||||
|
exit_status += make_status
|
||||||
|
|
||||||
|
if self.args.buck and exit_status == os.EX_OK:
|
||||||
|
clean_infer_out(self.args.infer_out)
|
||||||
|
|
||||||
|
cfgs = os.path.join(self.args.infer_out, 'captured', '*', '*.cfg')
|
||||||
|
captured_total = len(glob.glob(cfgs))
|
||||||
|
captured_plural = '' if captured_total <= 1 else 's'
|
||||||
|
print('\n%d file%s analyzed' % (captured_total, captured_plural))
|
||||||
|
|
||||||
|
return exit_status
|
||||||
|
|
||||||
|
def file_stats(self, file, stats):
|
||||||
|
if file is not None:
|
||||||
|
stats['files'] += 1
|
||||||
|
try:
|
||||||
|
with open(file, 'r') as f:
|
||||||
|
stats['lines'] += len(list(f))
|
||||||
|
except IOError:
|
||||||
|
logging.warning('File {} not found'.format(file))
|
||||||
|
|
||||||
|
|
||||||
|
def javac_stats(self):
|
||||||
|
stats = {'files': 0, 'lines': 0}
|
||||||
|
|
||||||
|
for arg in self.javac.original_arguments:
|
||||||
|
file = None
|
||||||
|
if arg.endswith('.java'):
|
||||||
|
file = arg
|
||||||
|
self.file_stats(file, stats)
|
||||||
|
if arg.startswith('@'):
|
||||||
|
with open(arg[1:], 'r') as f:
|
||||||
|
for line in f:
|
||||||
|
file = line.strip()
|
||||||
|
self.file_stats(file, stats)
|
||||||
|
|
||||||
|
return stats
|
||||||
|
|
||||||
|
def update_stats(self, csv_report):
|
||||||
|
with open(csv_report, 'r') as file_in:
|
||||||
|
reader = csv.reader(file_in)
|
||||||
|
rows = [row for row in reader][1:]
|
||||||
|
for row in rows:
|
||||||
|
key = row[utils.CSV_INDEX_TYPE]
|
||||||
|
previous_value = self.stats['int'].get(key, 0)
|
||||||
|
self.stats['int'][key] = previous_value + 1
|
||||||
|
|
||||||
|
def report_errors(self):
|
||||||
|
"""Report statistics about the computation and create a CSV file
|
||||||
|
containing the list or errors found during the analysis"""
|
||||||
|
|
||||||
|
csv_report = os.path.join(self.args.infer_out,
|
||||||
|
utils.CSV_REPORT_FILENAME)
|
||||||
|
bugs_out = os.path.join(self.args.infer_out,
|
||||||
|
utils.BUGS_FILENAME)
|
||||||
|
procs_report = os.path.join(self.args.infer_out, 'procs.csv')
|
||||||
|
|
||||||
|
infer_print_cmd = [utils.get_cmd_in_bin_dir('InferPrint')]
|
||||||
|
infer_print_options = [
|
||||||
|
'-q',
|
||||||
|
'-results_dir', self.args.infer_out,
|
||||||
|
'-bugs', csv_report,
|
||||||
|
'-procs', procs_report,
|
||||||
|
'-analyzer', self.args.analyzer
|
||||||
|
]
|
||||||
|
exit_status = subprocess.check_call(
|
||||||
|
infer_print_cmd + infer_print_options
|
||||||
|
)
|
||||||
|
if exit_status != os.EX_OK:
|
||||||
|
logging.error('Error with InferPrint with the command: '
|
||||||
|
+ infer_print_cmd)
|
||||||
|
else:
|
||||||
|
sort_csv(csv_report, self.args.infer_out)
|
||||||
|
self.update_stats(csv_report)
|
||||||
|
utils.create_json_report(self.args.infer_out)
|
||||||
|
|
||||||
|
print('\n')
|
||||||
|
if not self.args.buck:
|
||||||
|
print_errors(csv_report, bugs_out, self.args.analyzer)
|
||||||
|
|
||||||
|
return exit_status
|
||||||
|
|
||||||
|
def save_stats(self):
|
||||||
|
"""Print timing information to infer_out/stats.json"""
|
||||||
|
stats_path = os.path.join(self.args.infer_out, utils.STATS_FILENAME)
|
||||||
|
|
||||||
|
self.stats['int'].update(self.javac_stats())
|
||||||
|
|
||||||
|
self.stats['float'].update({
|
||||||
|
'capture_time': self.timing.get('capture', 0.0),
|
||||||
|
'analysis_time': self.timing.get('analysis', 0.0),
|
||||||
|
'reporting_time': self.timing.get('reporting', 0.0),
|
||||||
|
})
|
||||||
|
|
||||||
|
# Adding the analyzer and the version of Infer
|
||||||
|
self.stats['normal'] = {}
|
||||||
|
self.stats['normal']['analyzer'] = self.args.analyzer
|
||||||
|
self.stats['normal']['infer_version'] = utils.infer_version()
|
||||||
|
|
||||||
|
with open(stats_path, 'w') as stats_file:
|
||||||
|
json.dump(self.stats, stats_file)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if self.args.analyzer != COMPILE:
|
||||||
|
os.remove(self.javac.verbose_out)
|
||||||
|
|
||||||
|
def analyze_and_report(self):
|
||||||
|
if self.args.analyzer not in [COMPILE, CAPTURE]:
|
||||||
|
analysis_start_time = time.time()
|
||||||
|
if self.analyze() == os.EX_OK:
|
||||||
|
elapsed = utils.elapsed_time(analysis_start_time)
|
||||||
|
self.timing['analysis'] = elapsed
|
||||||
|
reporting_start_time = time.time()
|
||||||
|
self.report_errors()
|
||||||
|
elapsed = utils.elapsed_time(reporting_start_time)
|
||||||
|
self.timing['reporting'] = elapsed
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
if self.javac.args.version:
|
||||||
|
if self.args.buck:
|
||||||
|
key = self.args.analyzer
|
||||||
|
if self.args.analyzer_mode:
|
||||||
|
key += '_' + self.args.analyzer_mode
|
||||||
|
print(utils.infer_key(key), file=sys.stderr)
|
||||||
|
else:
|
||||||
|
return self.javac.run()
|
||||||
|
else:
|
||||||
|
start_time = time.time()
|
||||||
|
if self.capture() == os.EX_OK:
|
||||||
|
self.timing['capture'] = utils.elapsed_time(start_time)
|
||||||
|
self.analyze_and_report()
|
||||||
|
self.close()
|
||||||
|
elapsed = utils.elapsed_time(start_time)
|
||||||
|
self.timing['total'] = elapsed
|
||||||
|
self.save_stats()
|
||||||
|
return self.stats
|
||||||
|
else:
|
||||||
|
return dict({})
|
||||||
|
|
||||||
|
# vim: set sw=4 ts=4 et:
|
@ -0,0 +1,52 @@
|
|||||||
|
# Copyright (c) 2009-2013 Monoidics ltd.
|
||||||
|
# Copyright (c) 2013- Facebook.
|
||||||
|
# All rights reserved.
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import tempfile
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
# javac options
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
current_directory = os.getcwd()
|
||||||
|
|
||||||
|
parser.add_argument('-version', action='store_true')
|
||||||
|
parser.add_argument('-cp', '-classpath', type=str, dest='classpath')
|
||||||
|
parser.add_argument('-bootclasspath', type=str)
|
||||||
|
parser.add_argument('-d', dest='classes_out')
|
||||||
|
|
||||||
|
|
||||||
|
class CompilerCall:
|
||||||
|
|
||||||
|
def __init__(self, arguments):
|
||||||
|
|
||||||
|
self.original_arguments = arguments
|
||||||
|
self.args, _ = parser.parse_known_args(arguments)
|
||||||
|
self.verbose_out = None
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
if self.args.version:
|
||||||
|
return subprocess.call(['javac'] + self.original_arguments)
|
||||||
|
else:
|
||||||
|
javac_cmd = ['javac', '-verbose', '-g'] + self.original_arguments
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile(
|
||||||
|
mode='w',
|
||||||
|
suffix='.out',
|
||||||
|
prefix='javac_',
|
||||||
|
delete=False) as file_out:
|
||||||
|
self.verbose_out = file_out.name
|
||||||
|
|
||||||
|
try:
|
||||||
|
subprocess.check_call(javac_cmd, stderr=file_out)
|
||||||
|
return os.EX_OK
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
error_msg = 'Javac compilation error with: \n\n{}\n'
|
||||||
|
failing_cmd = [arg for arg in javac_cmd
|
||||||
|
if arg != '-verbose']
|
||||||
|
logging.error(error_msg.format(failing_cmd))
|
||||||
|
os.system(' '.join(failing_cmd))
|
||||||
|
return exc.returncode
|
@ -0,0 +1,345 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2013- Facebook. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import fnmatch
|
||||||
|
import gzip
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import tempfile
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
BIN_DIRECTORY = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
LIB_DIRECTORY = os.path.join(BIN_DIRECTORY, '..', 'lib', 'java')
|
||||||
|
TMP_DIRECTORY = tempfile.gettempdir()
|
||||||
|
MODELS_JAR = os.path.join(LIB_DIRECTORY, 'models.jar')
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_INFER_OUT = os.path.join(os.getcwd(), 'infer-out')
|
||||||
|
CSV_PERF_FILENAME = 'performances.csv'
|
||||||
|
STATS_FILENAME = 'stats.json'
|
||||||
|
|
||||||
|
CSV_REPORT_FILENAME = 'report.csv'
|
||||||
|
JSON_REPORT_FILENAME = 'report.json'
|
||||||
|
BUGS_FILENAME = 'bugs.txt'
|
||||||
|
|
||||||
|
CSV_INDEX_KIND = 1
|
||||||
|
CSV_INDEX_TYPE = 2
|
||||||
|
CSV_INDEX_QUALIFIER = 3
|
||||||
|
CSV_INDEX_LINE = 5
|
||||||
|
CSV_INDEX_FILENAME = 8
|
||||||
|
CSV_INDEX_QUALIFIER_TAGS = 11
|
||||||
|
|
||||||
|
QUALIFIER_TAGS = 'qualifier_tags'
|
||||||
|
BUCKET_TAGS = 'bucket'
|
||||||
|
|
||||||
|
IOS_CAPTURE_ERRORS = 'errors'
|
||||||
|
IOS_BUILD_OUTPUT = 'build_output'
|
||||||
|
|
||||||
|
BUCK_INFER_OUT = 'infer'
|
||||||
|
|
||||||
|
FORMAT = '[%(levelname)s] %(message)s'
|
||||||
|
DEBUG_FORMAT = '[%(levelname)s:%(filename)s:%(lineno)03d] %(message)s'
|
||||||
|
|
||||||
|
|
||||||
|
# Monkey patching subprocess (I'm so sorry!).
|
||||||
|
if "check_output" not in dir(subprocess):
|
||||||
|
def f(*popenargs, **kwargs):
|
||||||
|
if 'stdout' in kwargs:
|
||||||
|
raise ValueError('stdout not supported')
|
||||||
|
process = subprocess.Popen(
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
*popenargs,
|
||||||
|
**kwargs)
|
||||||
|
output, unused_err = process.communicate()
|
||||||
|
retcode = process.poll()
|
||||||
|
if retcode:
|
||||||
|
cmd = kwargs.get("args")
|
||||||
|
if cmd is None:
|
||||||
|
cmd = popenargs[0]
|
||||||
|
raise subprocess.CalledProcessError(retcode, cmd)
|
||||||
|
return output
|
||||||
|
subprocess.check_output = f
|
||||||
|
|
||||||
|
|
||||||
|
def configure_logging(debug, quiet=False):
|
||||||
|
"""Configures the default logger. This can be called only once and has to
|
||||||
|
be called before any logging is done.
|
||||||
|
"""
|
||||||
|
logging.TIMING = logging.ERROR + 5
|
||||||
|
logging.addLevelName(logging.TIMING, "TIMING")
|
||||||
|
|
||||||
|
def timing(msg, *args, **kwargs):
|
||||||
|
logging.log(logging.TIMING, msg, *args, **kwargs)
|
||||||
|
|
||||||
|
logging.timing = timing
|
||||||
|
if quiet:
|
||||||
|
logging.basicConfig(level=logging.TIMING, format=FORMAT)
|
||||||
|
elif not debug:
|
||||||
|
logging.basicConfig(level=logging.INFO, format=FORMAT)
|
||||||
|
else:
|
||||||
|
logging.basicConfig(level=logging.DEBUG, format=DEBUG_FORMAT)
|
||||||
|
|
||||||
|
|
||||||
|
def elapsed_time(start_time):
|
||||||
|
return time.time() - start_time
|
||||||
|
|
||||||
|
|
||||||
|
def error(msg):
|
||||||
|
print(msg, file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
|
def get_cmd_in_bin_dir(binary_name):
|
||||||
|
# this relies on the fact that utils.py is located in infer/bin
|
||||||
|
return os.path.join(
|
||||||
|
os.path.dirname(os.path.realpath(__file__)),
|
||||||
|
binary_name)
|
||||||
|
|
||||||
|
|
||||||
|
def write_cmd_streams_to_file(logfile, cmd=None, out=None, err=None):
|
||||||
|
with open(logfile, 'w') as log_filedesc:
|
||||||
|
if cmd:
|
||||||
|
log_filedesc.write(' '.join(cmd) + '\n')
|
||||||
|
if err is not None:
|
||||||
|
errors = str(err)
|
||||||
|
log_filedesc.write('\nSTDERR:\n')
|
||||||
|
log_filedesc.write(errors)
|
||||||
|
if out is not None:
|
||||||
|
output = str(out)
|
||||||
|
log_filedesc.write('\n\nSTDOUT:\n')
|
||||||
|
log_filedesc.write(output)
|
||||||
|
|
||||||
|
|
||||||
|
def save_failed_command(
|
||||||
|
infer_out,
|
||||||
|
cmd,
|
||||||
|
message,
|
||||||
|
prefix='failed_',
|
||||||
|
out=None,
|
||||||
|
err=None):
|
||||||
|
cmd_filename = tempfile.mktemp(
|
||||||
|
'_' + message + ".txt",
|
||||||
|
prefix, infer_out
|
||||||
|
)
|
||||||
|
write_cmd_streams_to_file(cmd_filename, cmd=cmd, out=out, err=err)
|
||||||
|
logging.error('\n' + message + ' error saved in ' + cmd_filename)
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(cmd, debug_mode, infer_out, message, env=os.environ):
|
||||||
|
if debug_mode:
|
||||||
|
print('\n{0}\n'.format(' '.join(cmd)))
|
||||||
|
try:
|
||||||
|
return subprocess.check_call(cmd, env=env)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
save_failed_command(infer_out, cmd, message)
|
||||||
|
raise e
|
||||||
|
|
||||||
|
|
||||||
|
def print_exit(s):
|
||||||
|
print(s)
|
||||||
|
exit(os.EX_OK)
|
||||||
|
|
||||||
|
|
||||||
|
def infer_version():
|
||||||
|
version = json.loads(subprocess.check_output([
|
||||||
|
get_cmd_in_bin_dir('InferAnalyze'),
|
||||||
|
'-version_json',
|
||||||
|
]).decode())
|
||||||
|
return version['commit']
|
||||||
|
|
||||||
|
|
||||||
|
def infer_branch():
|
||||||
|
version = json.loads(subprocess.check_output([
|
||||||
|
get_cmd_in_bin_dir('InferAnalyze'),
|
||||||
|
'-version_json',
|
||||||
|
]).decode())
|
||||||
|
return version['branch']
|
||||||
|
|
||||||
|
|
||||||
|
def infer_key(analyzer):
|
||||||
|
return os.pathsep.join([analyzer, infer_version()])
|
||||||
|
|
||||||
|
|
||||||
|
def vcs_branch(dir='.'):
|
||||||
|
cwd = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir(dir)
|
||||||
|
|
||||||
|
branch = subprocess.check_output([
|
||||||
|
'git',
|
||||||
|
'rev-parse',
|
||||||
|
'--abbrev-ref',
|
||||||
|
'HEAD',
|
||||||
|
]).decode().strip()
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
try:
|
||||||
|
branch = subprocess.check_output([
|
||||||
|
'hg',
|
||||||
|
'id',
|
||||||
|
'-B',
|
||||||
|
]).decode().strip()
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
branch = 'not-versioned'
|
||||||
|
finally:
|
||||||
|
os.chdir(cwd)
|
||||||
|
return branch
|
||||||
|
|
||||||
|
|
||||||
|
def vcs_revision(dir='.'):
|
||||||
|
cwd = os.getcwd()
|
||||||
|
try:
|
||||||
|
os.chdir(dir)
|
||||||
|
|
||||||
|
revision = subprocess.check_output([
|
||||||
|
'git',
|
||||||
|
'rev-parse',
|
||||||
|
'HEAD',
|
||||||
|
]).decode().strip()
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
try:
|
||||||
|
revision = subprocess.check_output([
|
||||||
|
'hg',
|
||||||
|
'id',
|
||||||
|
'-i',
|
||||||
|
]).decode().strip()
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
revision = 'not-versioned'
|
||||||
|
finally:
|
||||||
|
os.chdir(cwd)
|
||||||
|
return revision
|
||||||
|
|
||||||
|
|
||||||
|
class Timer:
|
||||||
|
"""Simple logging timer. Initialize with a printf like logging function."""
|
||||||
|
def __init__(self, logger=lambda x: None):
|
||||||
|
self._logger = logger
|
||||||
|
self._start = 0
|
||||||
|
|
||||||
|
def start(self, message=None, *args):
|
||||||
|
self._start = time.time()
|
||||||
|
if message:
|
||||||
|
self._logger(message, *args)
|
||||||
|
|
||||||
|
def stop(self, message=None, *args):
|
||||||
|
self._stop = time.time()
|
||||||
|
self._dt = self._stop - self._start
|
||||||
|
if message:
|
||||||
|
self._logger(message + ' (%.2fs)', *(args + (self._dt,)))
|
||||||
|
return self._dt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def interact():
|
||||||
|
"""Start interactive mode. Useful for debugging.
|
||||||
|
"""
|
||||||
|
import code
|
||||||
|
code.interact(local=locals())
|
||||||
|
|
||||||
|
|
||||||
|
def search_files(root_dir, extension):
|
||||||
|
# Input:
|
||||||
|
# - root directory where to start a recursive search of yjson files
|
||||||
|
# - file extension to search from the root
|
||||||
|
# Output:
|
||||||
|
# - list of absolute filepaths
|
||||||
|
files = []
|
||||||
|
if not os.path.isabs(root_dir):
|
||||||
|
root_dir = os.path.abspath(root_dir)
|
||||||
|
for dirpath, _, filenames in os.walk(root_dir):
|
||||||
|
for filename in fnmatch.filter(filenames, "*" + extension):
|
||||||
|
files.append(os.path.join(dirpath, filename))
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
def uncompress_gzip_file(gzip_file, out_dir):
|
||||||
|
# This is python2.6 compliant, gzip.open doesn't support 'with' statement
|
||||||
|
# Input:
|
||||||
|
# - gzip file path
|
||||||
|
# - output directory where uncompress the file
|
||||||
|
# Output:
|
||||||
|
# - path of the uncompressed file
|
||||||
|
# NOTE: the file is permanently created, is responsibility of the
|
||||||
|
# caller to delete it
|
||||||
|
uncompressed_path = None
|
||||||
|
uncompressed_fd = None
|
||||||
|
compressed_fd = None
|
||||||
|
try:
|
||||||
|
# the uncompressed filename loses its final extension
|
||||||
|
# (for example abc.gz -> abc)
|
||||||
|
uncompressed_path = os.path.join(
|
||||||
|
out_dir,
|
||||||
|
os.path.splitext(gzip_file)[0],
|
||||||
|
)
|
||||||
|
uncompressed_fd = open(uncompressed_path, 'wb')
|
||||||
|
compressed_fd = gzip.open(gzip_file, 'rb')
|
||||||
|
uncompressed_fd.write(compressed_fd.read())
|
||||||
|
return uncompressed_path
|
||||||
|
except IOError as exc:
|
||||||
|
# delete the uncompressed file (if exists)
|
||||||
|
if uncompressed_path is not None and os.path.exists(uncompressed_path):
|
||||||
|
os.remove(uncompressed_path)
|
||||||
|
raise exc
|
||||||
|
finally:
|
||||||
|
if compressed_fd is not None:
|
||||||
|
compressed_fd.close()
|
||||||
|
if uncompressed_fd is not None:
|
||||||
|
uncompressed_fd.close()
|
||||||
|
|
||||||
|
|
||||||
|
def run_process(cmd, cwd=None, logfile=None):
|
||||||
|
# Input:
|
||||||
|
# - command to execute
|
||||||
|
# - current working directory to cd before running the cmd
|
||||||
|
# - logfile where to dump stdout/stderr
|
||||||
|
# Output:
|
||||||
|
# - exitcode of the executed process
|
||||||
|
p = subprocess.Popen(
|
||||||
|
cmd,
|
||||||
|
cwd=cwd,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
(out, err) = p.communicate()
|
||||||
|
if logfile:
|
||||||
|
write_cmd_streams_to_file(logfile, cmd=cmd, out=out, err=err)
|
||||||
|
return p.returncode
|
||||||
|
|
||||||
|
|
||||||
|
def invoke_function_with_callbacks(
|
||||||
|
func,
|
||||||
|
args,
|
||||||
|
on_terminate=None,
|
||||||
|
on_exception=None):
|
||||||
|
try:
|
||||||
|
res = func(*args)
|
||||||
|
if on_terminate:
|
||||||
|
on_terminate(res)
|
||||||
|
return res
|
||||||
|
except Exception as exc:
|
||||||
|
if on_exception:
|
||||||
|
return on_exception(exc)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def create_json_report(out_dir):
|
||||||
|
csv_report_filename = os.path.join(out_dir, CSV_REPORT_FILENAME)
|
||||||
|
json_report_filename = os.path.join(out_dir, JSON_REPORT_FILENAME)
|
||||||
|
rows = []
|
||||||
|
with open(csv_report_filename, 'r') as file_in:
|
||||||
|
reader = csv.reader(file_in)
|
||||||
|
rows = [row for row in reader]
|
||||||
|
with open(json_report_filename, 'w') as file_out:
|
||||||
|
headers = rows[0]
|
||||||
|
issues = rows[1:]
|
||||||
|
json.dump([dict(zip(headers, row)) for row in issues], file_out)
|
||||||
|
|
||||||
|
# vim: set sw=4 ts=4 et:
|
@ -0,0 +1,24 @@
|
|||||||
|
import os
|
||||||
|
import util
|
||||||
|
|
||||||
|
MODULE_NAME = __name__
|
||||||
|
MODULE_DESCRIPTION = '''Run analysis of what has already been captured:
|
||||||
|
Usage:
|
||||||
|
infer -- analyze
|
||||||
|
infer --out <capture_folder> -- analyze'''
|
||||||
|
|
||||||
|
|
||||||
|
def gen_instance(*args):
|
||||||
|
return NoCapture(*args)
|
||||||
|
|
||||||
|
# This creates an empty argparser for the module, which provides only
|
||||||
|
# description/usage information and no arguments.
|
||||||
|
create_argparser = util.base_argparser(MODULE_DESCRIPTION, MODULE_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
class NoCapture:
|
||||||
|
def __init__(self, args, cmd):
|
||||||
|
self.args = args
|
||||||
|
|
||||||
|
def capture(self):
|
||||||
|
return os.EX_OK
|
@ -0,0 +1,69 @@
|
|||||||
|
import os
|
||||||
|
import util
|
||||||
|
|
||||||
|
MODULE_NAME = __name__
|
||||||
|
MODULE_DESCRIPTION = '''Run analysis of code built with a command like:
|
||||||
|
ant [options] [target]
|
||||||
|
|
||||||
|
Analysis examples:
|
||||||
|
infer -- ant compile'''
|
||||||
|
|
||||||
|
def gen_instance(*args):
|
||||||
|
return AntCapture(*args)
|
||||||
|
|
||||||
|
# This creates an empty argparser for the module, which provides only
|
||||||
|
# description/usage information and no arguments.
|
||||||
|
create_argparser = util.base_argparser(MODULE_DESCRIPTION, MODULE_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
class AntCapture:
|
||||||
|
|
||||||
|
def __init__(self, args, cmd):
|
||||||
|
self.args = args
|
||||||
|
# TODO: make the extraction of targets smarter
|
||||||
|
self.build_cmd = ['ant', '-verbose'] + cmd[1:]
|
||||||
|
|
||||||
|
def is_interesting(self, content):
|
||||||
|
return self.is_quoted(content) or content.endswith('.java')
|
||||||
|
|
||||||
|
def is_quoted(self, argument):
|
||||||
|
quote = '\''
|
||||||
|
return len(argument) > 2 and argument[0] == quote\
|
||||||
|
and argument[-1] == quote
|
||||||
|
|
||||||
|
def remove_quotes(self, argument):
|
||||||
|
if self.is_quoted(argument):
|
||||||
|
return argument[1:-1]
|
||||||
|
else:
|
||||||
|
return argument
|
||||||
|
|
||||||
|
def get_inferJ_commands(self, verbose_output):
|
||||||
|
javac_pattern = '[javac]'
|
||||||
|
argument_start_pattern = 'Compilation arguments'
|
||||||
|
calls = []
|
||||||
|
javac_arguments = []
|
||||||
|
collect = False
|
||||||
|
for line in verbose_output:
|
||||||
|
if javac_pattern in line:
|
||||||
|
if argument_start_pattern in line:
|
||||||
|
collect = True
|
||||||
|
if javac_arguments != []:
|
||||||
|
capture = util.create_inferJ_command(self.args,
|
||||||
|
javac_arguments)
|
||||||
|
calls.append(capture)
|
||||||
|
javac_arguments = []
|
||||||
|
if collect:
|
||||||
|
pos = line.index(javac_pattern) + len(javac_pattern)
|
||||||
|
content = line[pos:].strip()
|
||||||
|
if self.is_interesting(content):
|
||||||
|
arg = self.remove_quotes(content)
|
||||||
|
javac_arguments.append(arg)
|
||||||
|
if javac_arguments != []:
|
||||||
|
capture = util.create_inferJ_command(self.args, javac_arguments)
|
||||||
|
calls.append(capture)
|
||||||
|
javac_arguments = []
|
||||||
|
return calls
|
||||||
|
|
||||||
|
def capture(self):
|
||||||
|
cmds = self.get_inferJ_commands(util.get_build_output(self.build_cmd))
|
||||||
|
return util.run_commands(cmds)
|
@ -0,0 +1,42 @@
|
|||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import traceback
|
||||||
|
import util
|
||||||
|
|
||||||
|
import utils # this is module located in ../utils.py
|
||||||
|
|
||||||
|
MODULE_NAME = __name__
|
||||||
|
MODULE_DESCRIPTION = '''Run analysis of code built with a command like:
|
||||||
|
buck [options] [target]
|
||||||
|
|
||||||
|
Analysis examples:
|
||||||
|
infer -- buck build HelloWorld'''
|
||||||
|
|
||||||
|
|
||||||
|
def gen_instance(*args):
|
||||||
|
return BuckAnalyzer(*args)
|
||||||
|
|
||||||
|
# This creates an empty argparser for the module, which provides only
|
||||||
|
# description/usage information and no arguments.
|
||||||
|
create_argparser = util.base_argparser(MODULE_DESCRIPTION, MODULE_NAME)
|
||||||
|
|
||||||
|
|
||||||
|
class BuckAnalyzer:
|
||||||
|
def __init__(self, args, cmd):
|
||||||
|
self.args = args
|
||||||
|
self.cmd = cmd[2:] # TODO: make the extraction of targets smarter
|
||||||
|
|
||||||
|
def capture(self):
|
||||||
|
# BuckAnalyze is a special case, and we run the analysis from here
|
||||||
|
capture_cmd = [utils.get_cmd_in_bin_dir('BuckAnalyze')]
|
||||||
|
if self.args.debug:
|
||||||
|
capture_cmd.append('-g')
|
||||||
|
capture_cmd += self.cmd
|
||||||
|
capture_cmd += ['--analyzer', self.args.analyzer]
|
||||||
|
try:
|
||||||
|
subprocess.check_call(capture_cmd)
|
||||||
|
return os.EX_OK
|
||||||
|
except subprocess.CalledProcessError as exc:
|
||||||
|
if self.args.debug:
|
||||||
|
traceback.print_exc()
|
||||||
|
return exc.returncode
|
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
|
||||||
|
if [ "${0%++}" != "$0" ]; then XX="++"; else XX=""; fi
|
||||||
|
|
||||||
|
export FCP_CLANG_COMPILER="${SCRIPT_PATH%/}/../clang/clang_wrapper$XX";
|
||||||
|
export FCP_RESULTS_DIR="${INFER_RESULTS_DIR}";
|
||||||
|
export FCP_USE_STD_CLANG_CMD="1";
|
||||||
|
|
||||||
|
if [ -z $INFER_RESULTS_DIR ]; then
|
||||||
|
# this redirects to the compiler without adding any FCP flag
|
||||||
|
# this is because xcode requires message category info from the compiler
|
||||||
|
# and invokes it without any env var set.
|
||||||
|
"$FCP_CLANG_COMPILER" "$@"
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
|
|
||||||
|
"${SCRIPT_PATH%/}/../clang/clang_general_wrapper$XX" "$@"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue